1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "include/compat.h"
5 #include "common/ceph_context.h"
6 #include "common/config.h"
7 #include "common/snap_types.h"
8 #include "common/Clock.h"
9 #include "common/bit_vector.hpp"
10 #include "include/encoding.h"
11 #include "include/types.h"
12 #include "include/rados/librados.h"
13 #include "include/rbd/object_map_types.h"
14 #include "include/rbd_types.h"
15 #include "include/stringify.h"
16 #include "cls/rbd/cls_rbd.h"
17 #include "cls/rbd/cls_rbd_client.h"
18 #include "cls/rbd/cls_rbd_types.h"
19 #include "librbd/Types.h"
21 #include "gtest/gtest.h"
22 #include "test/librados/test_cxx.h"
29 using namespace librbd::cls_client
;
30 using cls::rbd::MIRROR_PEER_DIRECTION_RX
;
31 using cls::rbd::MIRROR_PEER_DIRECTION_TX
;
32 using cls::rbd::MIRROR_PEER_DIRECTION_RX_TX
;
33 using ::librbd::ParentImageInfo
;
37 static int snapshot_add(librados::IoCtx
*ioctx
, const std::string
&oid
,
38 uint64_t snap_id
, const std::string
&snap_name
) {
39 librados::ObjectWriteOperation op
;
40 ::librbd::cls_client::snapshot_add(&op
, snap_id
, snap_name
, cls::rbd::UserSnapshotNamespace());
41 return ioctx
->operate(oid
, &op
);
44 static int snapshot_remove(librados::IoCtx
*ioctx
, const std::string
&oid
,
46 librados::ObjectWriteOperation op
;
47 ::librbd::cls_client::snapshot_remove(&op
, snap_id
);
48 return ioctx
->operate(oid
, &op
);
51 static int snapshot_rename(librados::IoCtx
*ioctx
, const std::string
&oid
,
52 uint64_t snap_id
, const std::string
&snap_name
) {
53 librados::ObjectWriteOperation op
;
54 ::librbd::cls_client::snapshot_rename(&op
, snap_id
, snap_name
);
55 return ioctx
->operate(oid
, &op
);
58 static int old_snapshot_add(librados::IoCtx
*ioctx
, const std::string
&oid
,
59 uint64_t snap_id
, const std::string
&snap_name
) {
60 librados::ObjectWriteOperation op
;
61 ::librbd::cls_client::old_snapshot_add(&op
, snap_id
, snap_name
);
62 return ioctx
->operate(oid
, &op
);
65 static char *random_buf(size_t len
)
67 char *b
= new char[len
];
68 for (size_t i
= 0; i
< len
; i
++)
69 b
[i
] = (rand() % (128 - 32)) + 32;
73 static bool is_sparse_read_supported(librados::IoCtx
&ioctx
,
74 const std::string
&oid
) {
75 EXPECT_EQ(0, ioctx
.create(oid
, true));
77 inbl
.append(std::string(1, 'X'));
78 EXPECT_EQ(0, ioctx
.write(oid
, inbl
, inbl
.length(), 1));
79 EXPECT_EQ(0, ioctx
.write(oid
, inbl
, inbl
.length(), 3));
81 std::map
<uint64_t, uint64_t> m
;
83 int r
= ioctx
.sparse_read(oid
, m
, outbl
, 4, 0);
87 std::map
<uint64_t, uint64_t> expected_m
= {{1, 1}, {3, 1}};
88 bufferlist expected_outbl
;
89 expected_outbl
.append(std::string(2, 'X'));
91 return (r
== expected_r
&& m
== expected_m
&&
92 outbl
.contents_equal(expected_outbl
));
95 class TestClsRbd
: public ::testing::Test
{
98 static void SetUpTestCase() {
99 _pool_name
= get_temp_pool_name();
100 ASSERT_EQ("", create_one_pool_pp(_pool_name
, _rados
));
103 static void TearDownTestCase() {
104 ASSERT_EQ(0, destroy_one_pool_pp(_pool_name
, _rados
));
107 std::string
get_temp_image_name() {
109 return "image" + stringify(_image_number
);
112 static std::string _pool_name
;
113 static librados::Rados _rados
;
114 static uint64_t _image_number
;
118 std::string
TestClsRbd::_pool_name
;
119 librados::Rados
TestClsRbd::_rados
;
120 uint64_t TestClsRbd::_image_number
= 0;
122 TEST_F(TestClsRbd
, get_all_features
)
124 librados::IoCtx ioctx
;
125 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
127 string oid
= get_temp_image_name();
128 ASSERT_EQ(0, ioctx
.create(oid
, false));
130 uint64_t all_features
= 0;
131 ASSERT_EQ(0, get_all_features(&ioctx
, oid
, &all_features
));
132 ASSERT_EQ(static_cast<uint64_t>(RBD_FEATURES_ALL
),
133 static_cast<uint64_t>(all_features
& RBD_FEATURES_ALL
));
138 TEST_F(TestClsRbd
, copyup
)
140 librados::IoCtx ioctx
;
141 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
143 string oid
= get_temp_image_name();
144 bufferlist inbl
, outbl
;
146 // copyup of 0-len nonexistent object should create new 0-len object
148 ASSERT_EQ(0, copyup(&ioctx
, oid
, inbl
));
150 ASSERT_EQ(0, ioctx
.stat(oid
, &size
, NULL
));
153 // create some random data to write
155 char *b
= random_buf(l
);
158 ASSERT_EQ(l
, inbl
.length());
160 // copyup to nonexistent object should create new object
162 ASSERT_EQ(-ENOENT
, ioctx
.remove(oid
));
163 ASSERT_EQ(0, copyup(&ioctx
, oid
, inbl
));
164 // and its contents should match
165 ASSERT_EQ(l
, (size_t)ioctx
.read(oid
, outbl
, l
, 0));
166 ASSERT_TRUE(outbl
.contents_equal(inbl
));
168 // now send different data, but with a preexisting object
173 ASSERT_EQ(l
, inbl2
.length());
175 // should still succeed
176 ASSERT_EQ(0, copyup(&ioctx
, oid
, inbl
));
177 ASSERT_EQ(l
, (size_t)ioctx
.read(oid
, outbl
, l
, 0));
178 // but contents should not have changed
179 ASSERT_FALSE(outbl
.contents_equal(inbl2
));
180 ASSERT_TRUE(outbl
.contents_equal(inbl
));
182 ASSERT_EQ(0, ioctx
.remove(oid
));
186 TEST_F(TestClsRbd
, sparse_copyup
)
188 librados::IoCtx ioctx
;
189 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
191 string oid
= get_temp_image_name();
194 bool sparse_read_supported
= is_sparse_read_supported(ioctx
, oid
);
196 // copyup of 0-len nonexistent object should create new 0-len object
198 ASSERT_EQ(-ENOENT
, ioctx
.stat(oid
, &size
, nullptr));
199 std::map
<uint64_t, uint64_t> m
;
201 ASSERT_EQ(0, sparse_copyup(&ioctx
, oid
, m
, inbl
));
202 ASSERT_EQ(0, ioctx
.stat(oid
, &size
, nullptr));
205 // create some data to write
206 inbl
.append(std::string(4096, '1'));
207 inbl
.append(std::string(4096, '2'));
208 m
= {{1024, 4096}, {8192, 4096}};
210 // copyup to nonexistent object should create new object
212 ASSERT_EQ(-ENOENT
, ioctx
.remove(oid
));
213 ASSERT_EQ(0, sparse_copyup(&ioctx
, oid
, m
, inbl
));
214 // and its contents should match
216 bufferlist expected_outbl
;
217 expected_outbl
.append(std::string(1024, '\0'));
218 expected_outbl
.append(std::string(4096, '1'));
219 expected_outbl
.append(std::string(8192 - 4096 - 1024, '\0'));
220 expected_outbl
.append(std::string(4096, '2'));
221 ASSERT_EQ((int)expected_outbl
.length(),
222 ioctx
.read(oid
, outbl
, expected_outbl
.length() + 1, 0));
223 ASSERT_TRUE(outbl
.contents_equal(expected_outbl
));
224 std::map
<uint64_t, uint64_t> expected_m
;
225 if (sparse_read_supported
) {
227 expected_outbl
= inbl
;
229 expected_m
= {{0, expected_outbl
.length()}};
233 ASSERT_EQ((int)expected_m
.size(), ioctx
.sparse_read(oid
, m
, outbl
, 65536, 0));
234 ASSERT_EQ(m
, expected_m
);
235 ASSERT_TRUE(outbl
.contents_equal(expected_outbl
));
237 // now send different data, but with a preexisting object
239 inbl2
.append(std::string(1024, 'X'));
241 // should still succeed
242 ASSERT_EQ(0, sparse_copyup(&ioctx
, oid
, {{0, 1024}}, inbl2
));
243 // but contents should not have changed
246 ASSERT_EQ((int)expected_m
.size(), ioctx
.sparse_read(oid
, m
, outbl
, 65536, 0));
247 ASSERT_EQ(m
, expected_m
);
248 ASSERT_TRUE(outbl
.contents_equal(expected_outbl
));
250 ASSERT_EQ(0, ioctx
.remove(oid
));
254 TEST_F(TestClsRbd
, get_and_set_id
)
256 librados::IoCtx ioctx
;
257 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
259 string oid
= get_temp_image_name();
261 string valid_id
= "0123abcxyzZYXCBA";
262 string invalid_id
= ".abc";
265 ASSERT_EQ(-ENOENT
, get_id(&ioctx
, oid
, &id
));
266 ASSERT_EQ(-ENOENT
, set_id(&ioctx
, oid
, valid_id
));
268 ASSERT_EQ(0, ioctx
.create(oid
, true));
269 ASSERT_EQ(-EINVAL
, set_id(&ioctx
, oid
, invalid_id
));
270 ASSERT_EQ(-EINVAL
, set_id(&ioctx
, oid
, empty_id
));
271 ASSERT_EQ(-ENOENT
, get_id(&ioctx
, oid
, &id
));
273 ASSERT_EQ(0, set_id(&ioctx
, oid
, valid_id
));
274 ASSERT_EQ(-EEXIST
, set_id(&ioctx
, oid
, valid_id
));
275 ASSERT_EQ(-EEXIST
, set_id(&ioctx
, oid
, valid_id
+ valid_id
));
276 ASSERT_EQ(0, get_id(&ioctx
, oid
, &id
));
277 ASSERT_EQ(id
, valid_id
);
282 TEST_F(TestClsRbd
, add_remove_child
)
284 librados::IoCtx ioctx
;
285 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
287 string oid
= get_temp_image_name();
288 ASSERT_EQ(0, ioctx
.create(oid
, true));
290 string snapname
= "parent_snap";
292 string parent_image
= "parent_id";
294 cls::rbd::ParentImageSpec
pspec(ioctx
.get_id(), "", parent_image
, snapid
);
296 // nonexistent children cannot be listed or removed
297 ASSERT_EQ(-ENOENT
, get_children(&ioctx
, oid
, pspec
, children
));
298 ASSERT_EQ(-ENOENT
, remove_child(&ioctx
, oid
, pspec
, "child1"));
300 // create the parent and snapshot
301 ASSERT_EQ(0, create_image(&ioctx
, parent_image
, 2<<20, 0,
302 RBD_FEATURE_LAYERING
, parent_image
, -1));
303 ASSERT_EQ(0, snapshot_add(&ioctx
, parent_image
, snapid
, snapname
));
305 // add child to it, verify it showed up
306 ASSERT_EQ(0, add_child(&ioctx
, oid
, pspec
, "child1"));
307 ASSERT_EQ(0, get_children(&ioctx
, oid
, pspec
, children
));
308 ASSERT_TRUE(children
.find("child1") != children
.end());
309 // add another child to it, verify it showed up
310 ASSERT_EQ(0, add_child(&ioctx
, oid
, pspec
, "child2"));
311 ASSERT_EQ(0, get_children(&ioctx
, oid
, pspec
, children
));
312 ASSERT_TRUE(children
.find("child2") != children
.end());
313 // add child2 again, expect -EEXIST
314 ASSERT_EQ(-EEXIST
, add_child(&ioctx
, oid
, pspec
, "child2"));
315 // remove first, verify it's gone
316 ASSERT_EQ(0, remove_child(&ioctx
, oid
, pspec
, "child1"));
317 ASSERT_EQ(0, get_children(&ioctx
, oid
, pspec
, children
));
318 ASSERT_FALSE(children
.find("child1") != children
.end());
319 // remove second, verify list empty
320 ASSERT_EQ(0, remove_child(&ioctx
, oid
, pspec
, "child2"));
321 ASSERT_EQ(-ENOENT
, get_children(&ioctx
, oid
, pspec
, children
));
322 // try to remove again, validate -ENOENT to that as well
323 ASSERT_EQ(-ENOENT
, remove_child(&ioctx
, oid
, pspec
, "child2"));
328 TEST_F(TestClsRbd
, directory_methods
)
330 librados::IoCtx ioctx
;
331 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
333 string oid
= get_temp_image_name();
335 string imgname
= get_temp_image_name();
336 string imgname2
= get_temp_image_name();
337 string imgname3
= get_temp_image_name();
338 string valid_id
= "0123abcxyzZYXCBA";
339 string valid_id2
= "5";
340 string invalid_id
= ".abc";
343 ASSERT_EQ(-ENOENT
, dir_state_assert(&ioctx
, oid
,
344 cls::rbd::DIRECTORY_STATE_READY
));
345 ASSERT_EQ(-ENOENT
, dir_state_set(&ioctx
, oid
,
346 cls::rbd::DIRECTORY_STATE_ADD_DISABLED
));
348 ASSERT_EQ(-ENOENT
, dir_get_id(&ioctx
, oid
, imgname
, &id
));
349 ASSERT_EQ(-ENOENT
, dir_get_name(&ioctx
, oid
, valid_id
, &name
));
350 ASSERT_EQ(-ENOENT
, dir_remove_image(&ioctx
, oid
, imgname
, valid_id
));
352 ASSERT_EQ(-EINVAL
, dir_add_image(&ioctx
, oid
, imgname
, invalid_id
));
353 ASSERT_EQ(-EINVAL
, dir_add_image(&ioctx
, oid
, imgname
, empty
));
354 ASSERT_EQ(-EINVAL
, dir_add_image(&ioctx
, oid
, empty
, valid_id
));
356 map
<string
, string
> images
;
357 ASSERT_EQ(-ENOENT
, dir_list(&ioctx
, oid
, "", 30, &images
));
359 ASSERT_EQ(0, ioctx
.create(oid
, true));
360 ASSERT_EQ(0, dir_list(&ioctx
, oid
, "", 30, &images
));
361 ASSERT_EQ(0u, images
.size());
362 ASSERT_EQ(0, ioctx
.remove(oid
));
364 ASSERT_EQ(0, dir_state_set(&ioctx
, oid
, cls::rbd::DIRECTORY_STATE_READY
));
365 ASSERT_EQ(0, dir_state_assert(&ioctx
, oid
, cls::rbd::DIRECTORY_STATE_READY
));
367 ASSERT_EQ(0, dir_add_image(&ioctx
, oid
, imgname
, valid_id
));
368 ASSERT_EQ(-EBUSY
, dir_state_set(&ioctx
, oid
,
369 cls::rbd::DIRECTORY_STATE_ADD_DISABLED
));
371 ASSERT_EQ(-EEXIST
, dir_add_image(&ioctx
, oid
, imgname
, valid_id2
));
372 ASSERT_EQ(-EBADF
, dir_add_image(&ioctx
, oid
, imgname2
, valid_id
));
373 ASSERT_EQ(0, dir_list(&ioctx
, oid
, "", 30, &images
));
374 ASSERT_EQ(1u, images
.size());
375 ASSERT_EQ(valid_id
, images
[imgname
]);
376 ASSERT_EQ(0, dir_list(&ioctx
, oid
, "", 0, &images
));
377 ASSERT_EQ(0u, images
.size());
378 ASSERT_EQ(0, dir_get_name(&ioctx
, oid
, valid_id
, &name
));
379 ASSERT_EQ(imgname
, name
);
380 ASSERT_EQ(0, dir_get_id(&ioctx
, oid
, imgname
, &id
));
381 ASSERT_EQ(valid_id
, id
);
383 ASSERT_EQ(0, dir_add_image(&ioctx
, oid
, imgname2
, valid_id2
));
384 ASSERT_EQ(0, dir_list(&ioctx
, oid
, "", 30, &images
));
385 ASSERT_EQ(2u, images
.size());
386 ASSERT_EQ(valid_id
, images
[imgname
]);
387 ASSERT_EQ(valid_id2
, images
[imgname2
]);
388 ASSERT_EQ(0, dir_list(&ioctx
, oid
, imgname
, 0, &images
));
389 ASSERT_EQ(0u, images
.size());
390 ASSERT_EQ(0, dir_list(&ioctx
, oid
, imgname
, 2, &images
));
391 ASSERT_EQ(1u, images
.size());
392 ASSERT_EQ(valid_id2
, images
[imgname2
]);
393 ASSERT_EQ(0, dir_get_name(&ioctx
, oid
, valid_id2
, &name
));
394 ASSERT_EQ(imgname2
, name
);
395 ASSERT_EQ(0, dir_get_id(&ioctx
, oid
, imgname2
, &id
));
396 ASSERT_EQ(valid_id2
, id
);
398 librados::ObjectWriteOperation op1
;
399 dir_rename_image(&op1
, imgname
, imgname2
, valid_id2
);
400 ASSERT_EQ(-ESTALE
, ioctx
.operate(oid
, &op1
));
401 ASSERT_EQ(-ESTALE
, dir_remove_image(&ioctx
, oid
, imgname
, valid_id2
));
402 librados::ObjectWriteOperation op2
;
403 dir_rename_image(&op2
, imgname
, imgname2
, valid_id
);
404 ASSERT_EQ(-EEXIST
, ioctx
.operate(oid
, &op2
));
405 ASSERT_EQ(0, dir_get_id(&ioctx
, oid
, imgname
, &id
));
406 ASSERT_EQ(valid_id
, id
);
407 ASSERT_EQ(0, dir_get_name(&ioctx
, oid
, valid_id2
, &name
));
408 ASSERT_EQ(imgname2
, name
);
410 librados::ObjectWriteOperation op3
;
411 dir_rename_image(&op3
, imgname
, imgname3
, valid_id
);
412 ASSERT_EQ(0, ioctx
.operate(oid
, &op3
));
413 ASSERT_EQ(0, dir_get_id(&ioctx
, oid
, imgname3
, &id
));
414 ASSERT_EQ(valid_id
, id
);
415 ASSERT_EQ(0, dir_get_name(&ioctx
, oid
, valid_id
, &name
));
416 ASSERT_EQ(imgname3
, name
);
417 librados::ObjectWriteOperation op4
;
418 dir_rename_image(&op4
, imgname3
, imgname
, valid_id
);
419 ASSERT_EQ(0, ioctx
.operate(oid
, &op4
));
421 ASSERT_EQ(0, dir_remove_image(&ioctx
, oid
, imgname
, valid_id
));
422 ASSERT_EQ(0, dir_list(&ioctx
, oid
, "", 30, &images
));
423 ASSERT_EQ(1u, images
.size());
424 ASSERT_EQ(valid_id2
, images
[imgname2
]);
425 ASSERT_EQ(0, dir_list(&ioctx
, oid
, imgname2
, 30, &images
));
426 ASSERT_EQ(0u, images
.size());
427 ASSERT_EQ(0, dir_get_name(&ioctx
, oid
, valid_id2
, &name
));
428 ASSERT_EQ(imgname2
, name
);
429 ASSERT_EQ(0, dir_get_id(&ioctx
, oid
, imgname2
, &id
));
430 ASSERT_EQ(valid_id2
, id
);
431 ASSERT_EQ(-ENOENT
, dir_get_name(&ioctx
, oid
, valid_id
, &name
));
432 ASSERT_EQ(-ENOENT
, dir_get_id(&ioctx
, oid
, imgname
, &id
));
434 ASSERT_EQ(0, dir_add_image(&ioctx
, oid
, imgname
, valid_id
));
435 ASSERT_EQ(0, dir_list(&ioctx
, oid
, "", 30, &images
));
436 ASSERT_EQ(2u, images
.size());
437 ASSERT_EQ(valid_id
, images
[imgname
]);
438 ASSERT_EQ(valid_id2
, images
[imgname2
]);
439 ASSERT_EQ(0, dir_remove_image(&ioctx
, oid
, imgname
, valid_id
));
440 ASSERT_EQ(-ENOENT
, dir_remove_image(&ioctx
, oid
, imgname
, valid_id
));
441 ASSERT_EQ(0, dir_remove_image(&ioctx
, oid
, imgname2
, valid_id2
));
442 ASSERT_EQ(0, dir_list(&ioctx
, oid
, "", 30, &images
));
443 ASSERT_EQ(0u, images
.size());
448 TEST_F(TestClsRbd
, create
)
450 librados::IoCtx ioctx
;
451 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
453 string oid
= get_temp_image_name();
454 uint64_t size
= 20ULL << 30;
455 uint64_t features
= 0;
457 string object_prefix
= oid
;
459 ASSERT_EQ(0, create_image(&ioctx
, oid
, size
, order
,
460 features
, object_prefix
, -1));
461 ASSERT_EQ(-EEXIST
, create_image(&ioctx
, oid
, size
, order
,
462 features
, object_prefix
, -1));
463 ASSERT_EQ(0, ioctx
.remove(oid
));
465 ASSERT_EQ(-EINVAL
, create_image(&ioctx
, oid
, size
, order
,
467 ASSERT_EQ(-ENOENT
, ioctx
.remove(oid
));
469 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, order
,
470 features
, object_prefix
, -1));
471 ASSERT_EQ(0, ioctx
.remove(oid
));
473 ASSERT_EQ(-ENOSYS
, create_image(&ioctx
, oid
, size
, order
,
474 -1, object_prefix
, -1));
475 ASSERT_EQ(-ENOENT
, ioctx
.remove(oid
));
477 ASSERT_EQ(0, create_image(&ioctx
, oid
, size
, order
, RBD_FEATURE_DATA_POOL
,
478 object_prefix
, 123));
479 ASSERT_EQ(0, ioctx
.remove(oid
));
480 ASSERT_EQ(-EINVAL
, create_image(&ioctx
, oid
, size
, order
,
481 RBD_FEATURE_OPERATIONS
, object_prefix
, -1));
482 ASSERT_EQ(-EINVAL
, create_image(&ioctx
, oid
, size
, order
,
483 RBD_FEATURE_DATA_POOL
, object_prefix
, -1));
484 ASSERT_EQ(-EINVAL
, create_image(&ioctx
, oid
, size
, order
, 0, object_prefix
,
487 bufferlist inbl
, outbl
;
488 ASSERT_EQ(-EINVAL
, ioctx
.exec(oid
, "rbd", "create", inbl
, outbl
));
493 TEST_F(TestClsRbd
, get_features
)
495 librados::IoCtx ioctx
;
496 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
498 string oid
= get_temp_image_name();
501 uint64_t incompatible_features
;
502 ASSERT_EQ(-ENOENT
, get_features(&ioctx
, oid
, false, &features
,
503 &incompatible_features
));
505 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
506 ASSERT_EQ(0, get_features(&ioctx
, oid
, false, &features
,
507 &incompatible_features
));
508 ASSERT_EQ(0u, features
);
512 TEST_F(TestClsRbd
, get_object_prefix
)
514 librados::IoCtx ioctx
;
515 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
517 string oid
= get_temp_image_name();
519 string object_prefix
;
520 ASSERT_EQ(-ENOENT
, get_object_prefix(&ioctx
, oid
, &object_prefix
));
522 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
523 ASSERT_EQ(0, get_object_prefix(&ioctx
, oid
, &object_prefix
));
524 ASSERT_EQ(oid
, object_prefix
);
529 TEST_F(TestClsRbd
, get_create_timestamp
)
531 librados::IoCtx ioctx
;
532 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
534 string oid
= get_temp_image_name();
535 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
538 ASSERT_EQ(0, get_create_timestamp(&ioctx
, oid
, ×tamp
));
539 ASSERT_LT(0U, timestamp
.tv
.tv_sec
);
544 TEST_F(TestClsRbd
, get_access_timestamp
)
546 librados::IoCtx ioctx
;
547 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
549 string oid
= get_temp_image_name();
550 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
553 ASSERT_EQ(0, get_access_timestamp(&ioctx
, oid
, ×tamp
));
554 ASSERT_LT(0U, timestamp
.tv
.tv_sec
);
558 TEST_F(TestClsRbd
, get_modify_timestamp
)
560 librados::IoCtx ioctx
;
561 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
563 string oid
= get_temp_image_name();
564 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
567 ASSERT_EQ(0, get_modify_timestamp(&ioctx
, oid
, ×tamp
));
568 ASSERT_LT(0U, timestamp
.tv
.tv_sec
);
572 TEST_F(TestClsRbd
, get_data_pool
)
574 librados::IoCtx ioctx
;
575 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
577 string oid
= get_temp_image_name();
579 int64_t data_pool_id
;
580 ASSERT_EQ(0, ioctx
.create(oid
, true));
581 ASSERT_EQ(0, get_data_pool(&ioctx
, oid
, &data_pool_id
));
582 ASSERT_EQ(-1, data_pool_id
);
583 ASSERT_EQ(0, ioctx
.remove(oid
));
585 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, RBD_FEATURE_DATA_POOL
, oid
,
587 ASSERT_EQ(0, get_data_pool(&ioctx
, oid
, &data_pool_id
));
588 ASSERT_EQ(12, data_pool_id
);
591 TEST_F(TestClsRbd
, get_size
)
593 librados::IoCtx ioctx
;
594 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
596 string oid
= get_temp_image_name();
599 ASSERT_EQ(-ENOENT
, get_size(&ioctx
, oid
, CEPH_NOSNAP
, &size
, &order
));
601 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
602 ASSERT_EQ(0, get_size(&ioctx
, oid
, CEPH_NOSNAP
, &size
, &order
));
604 ASSERT_EQ(22, order
);
605 ASSERT_EQ(0, ioctx
.remove(oid
));
607 ASSERT_EQ(0, create_image(&ioctx
, oid
, 2 << 22, 0, 0, oid
, -1));
608 ASSERT_EQ(0, get_size(&ioctx
, oid
, CEPH_NOSNAP
, &size
, &order
));
609 ASSERT_EQ(2u << 22, size
);
612 ASSERT_EQ(-ENOENT
, get_size(&ioctx
, oid
, 1, &size
, &order
));
617 TEST_F(TestClsRbd
, set_size
)
619 librados::IoCtx ioctx
;
620 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
622 string oid
= get_temp_image_name();
623 ASSERT_EQ(-ENOENT
, set_size(&ioctx
, oid
, 5));
627 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
628 ASSERT_EQ(0, get_size(&ioctx
, oid
, CEPH_NOSNAP
, &size
, &order
));
630 ASSERT_EQ(22, order
);
632 ASSERT_EQ(0, set_size(&ioctx
, oid
, 0));
633 ASSERT_EQ(0, get_size(&ioctx
, oid
, CEPH_NOSNAP
, &size
, &order
));
635 ASSERT_EQ(22, order
);
637 ASSERT_EQ(0, set_size(&ioctx
, oid
, 3 << 22));
638 ASSERT_EQ(0, get_size(&ioctx
, oid
, CEPH_NOSNAP
, &size
, &order
));
639 ASSERT_EQ(3u << 22, size
);
640 ASSERT_EQ(22, order
);
645 TEST_F(TestClsRbd
, protection_status
)
647 librados::IoCtx ioctx
;
648 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
650 string oid
= get_temp_image_name();
651 string oid2
= get_temp_image_name();
652 uint8_t status
= RBD_PROTECTION_STATUS_UNPROTECTED
;
653 ASSERT_EQ(-ENOENT
, get_protection_status(&ioctx
, oid
,
654 CEPH_NOSNAP
, &status
));
655 ASSERT_EQ(-ENOENT
, set_protection_status(&ioctx
, oid
,
656 CEPH_NOSNAP
, status
));
658 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, RBD_FEATURE_LAYERING
, oid
, -1));
659 ASSERT_EQ(0, create_image(&ioctx
, oid2
, 0, 22, 0, oid
, -1));
660 ASSERT_EQ(-EINVAL
, get_protection_status(&ioctx
, oid2
,
661 CEPH_NOSNAP
, &status
));
662 ASSERT_EQ(-ENOEXEC
, set_protection_status(&ioctx
, oid2
,
663 CEPH_NOSNAP
, status
));
664 ASSERT_EQ(-EINVAL
, get_protection_status(&ioctx
, oid
,
665 CEPH_NOSNAP
, &status
));
666 ASSERT_EQ(-EINVAL
, set_protection_status(&ioctx
, oid
,
667 CEPH_NOSNAP
, status
));
668 ASSERT_EQ(-ENOENT
, get_protection_status(&ioctx
, oid
,
670 ASSERT_EQ(-ENOENT
, set_protection_status(&ioctx
, oid
,
673 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 10, "snap1"));
674 ASSERT_EQ(0, get_protection_status(&ioctx
, oid
,
676 ASSERT_EQ(+RBD_PROTECTION_STATUS_UNPROTECTED
, status
);
678 ASSERT_EQ(0, set_protection_status(&ioctx
, oid
,
679 10, RBD_PROTECTION_STATUS_PROTECTED
));
680 ASSERT_EQ(0, get_protection_status(&ioctx
, oid
,
682 ASSERT_EQ(+RBD_PROTECTION_STATUS_PROTECTED
, status
);
683 ASSERT_EQ(-EBUSY
, snapshot_remove(&ioctx
, oid
, 10));
685 ASSERT_EQ(0, set_protection_status(&ioctx
, oid
,
686 10, RBD_PROTECTION_STATUS_UNPROTECTING
));
687 ASSERT_EQ(0, get_protection_status(&ioctx
, oid
,
689 ASSERT_EQ(+RBD_PROTECTION_STATUS_UNPROTECTING
, status
);
690 ASSERT_EQ(-EBUSY
, snapshot_remove(&ioctx
, oid
, 10));
692 ASSERT_EQ(-EINVAL
, set_protection_status(&ioctx
, oid
,
693 10, RBD_PROTECTION_STATUS_LAST
));
694 ASSERT_EQ(0, get_protection_status(&ioctx
, oid
,
696 ASSERT_EQ(+RBD_PROTECTION_STATUS_UNPROTECTING
, status
);
698 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 20, "snap2"));
699 ASSERT_EQ(0, get_protection_status(&ioctx
, oid
,
701 ASSERT_EQ(+RBD_PROTECTION_STATUS_UNPROTECTED
, status
);
702 ASSERT_EQ(0, set_protection_status(&ioctx
, oid
,
703 10, RBD_PROTECTION_STATUS_UNPROTECTED
));
704 ASSERT_EQ(0, get_protection_status(&ioctx
, oid
,
706 ASSERT_EQ(+RBD_PROTECTION_STATUS_UNPROTECTED
, status
);
708 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 10));
709 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 20));
714 TEST_F(TestClsRbd
, snapshot_limits
)
716 librados::IoCtx ioctx
;
717 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
719 librados::ObjectWriteOperation op
;
720 string oid
= get_temp_image_name();
723 ASSERT_EQ(-ENOENT
, snapshot_get_limit(&ioctx
, oid
, &limit
));
725 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, RBD_FEATURE_LAYERING
, oid
, -1));
727 // if snapshot doesn't set limit, the limit is UINT64_MAX
728 ASSERT_EQ(0, snapshot_get_limit(&ioctx
, oid
, &limit
));
729 ASSERT_EQ(UINT64_MAX
, limit
);
731 snapshot_set_limit(&op
, 2);
733 ASSERT_EQ(0, ioctx
.operate(oid
, &op
));
735 ASSERT_EQ(0, snapshot_get_limit(&ioctx
, oid
, &limit
));
736 ASSERT_EQ(2U, limit
);
738 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 10, "snap1"));
739 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 20, "snap2"));
740 ASSERT_EQ(-EDQUOT
, snapshot_add(&ioctx
, oid
, 30, "snap3"));
742 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 10));
743 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 20));
748 TEST_F(TestClsRbd
, parents_v1
)
750 librados::IoCtx ioctx
;
751 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
753 cls::rbd::ParentImageSpec pspec
;
756 ASSERT_EQ(-ENOENT
, get_parent(&ioctx
, "doesnotexist", CEPH_NOSNAP
, &pspec
, &size
));
758 // old image should fail
759 std::string oid
= get_temp_image_name();
760 ASSERT_EQ(0, create_image(&ioctx
, oid
, 33<<20, 22, 0, "old_blk.", -1));
761 // get nonexistent parent: succeed, return (-1, "", CEPH_NOSNAP), overlap 0
762 ASSERT_EQ(0, get_parent(&ioctx
, oid
, CEPH_NOSNAP
, &pspec
, &size
));
763 ASSERT_EQ(pspec
.pool_id
, -1);
764 ASSERT_STREQ("", pspec
.image_id
.c_str());
765 ASSERT_EQ(pspec
.snap_id
, CEPH_NOSNAP
);
766 ASSERT_EQ(size
, 0ULL);
767 pspec
= {-1, "", "parent", 3};
768 ASSERT_EQ(-ENOEXEC
, set_parent(&ioctx
, oid
, {-1, "", "parent", 3}, 10<<20));
769 ASSERT_EQ(-ENOEXEC
, remove_parent(&ioctx
, oid
));
771 // new image will work
772 oid
= get_temp_image_name();
773 ASSERT_EQ(0, create_image(&ioctx
, oid
, 33<<20, 22, RBD_FEATURE_LAYERING
,
776 ASSERT_EQ(0, get_parent(&ioctx
, oid
, CEPH_NOSNAP
, &pspec
, &size
));
777 ASSERT_EQ(-1, pspec
.pool_id
);
778 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 123, &pspec
, &size
));
779 ASSERT_EQ(-1, pspec
.pool_id
);
781 ASSERT_EQ(-EINVAL
, set_parent(&ioctx
, oid
, {-1, "", "parent", 3}, 10<<20));
782 ASSERT_EQ(-EINVAL
, set_parent(&ioctx
, oid
, {1, "", "", 3}, 10<<20));
783 ASSERT_EQ(-EINVAL
, set_parent(&ioctx
, oid
, {1, "", "parent", CEPH_NOSNAP
}, 10<<20));
784 ASSERT_EQ(-EINVAL
, set_parent(&ioctx
, oid
, {1, "", "parent", 3}, 0));
786 pspec
= {1, "", "parent", 3};
787 ASSERT_EQ(0, set_parent(&ioctx
, oid
, pspec
, 10<<20));
788 ASSERT_EQ(-EEXIST
, set_parent(&ioctx
, oid
, pspec
, 10<<20));
789 ASSERT_EQ(-EEXIST
, set_parent(&ioctx
, oid
, {2, "", "parent", 34}, 10<<20));
791 ASSERT_EQ(0, get_parent(&ioctx
, oid
, CEPH_NOSNAP
, &pspec
, &size
));
792 ASSERT_EQ(pspec
.pool_id
, 1);
793 ASSERT_EQ(pspec
.image_id
, "parent");
794 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
796 ASSERT_EQ(0, remove_parent(&ioctx
, oid
));
797 ASSERT_EQ(-ENOENT
, remove_parent(&ioctx
, oid
));
798 ASSERT_EQ(0, get_parent(&ioctx
, oid
, CEPH_NOSNAP
, &pspec
, &size
));
799 ASSERT_EQ(-1, pspec
.pool_id
);
802 ASSERT_EQ(0, set_parent(&ioctx
, oid
, {1, "", "parent", 3}, 10<<20));
803 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 10, "snap1"));
804 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 10, &pspec
, &size
));
805 ASSERT_EQ(pspec
.pool_id
, 1);
806 ASSERT_EQ(pspec
.image_id
, "parent");
807 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
808 ASSERT_EQ(size
, 10ull<<20);
810 ASSERT_EQ(0, remove_parent(&ioctx
, oid
));
811 ASSERT_EQ(0, set_parent(&ioctx
, oid
, {1, "", "parent", 3}, 5<<20));
812 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 11, "snap2"));
813 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 10, &pspec
, &size
));
814 ASSERT_EQ(pspec
.pool_id
, 1);
815 ASSERT_EQ(pspec
.image_id
, "parent");
816 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
817 ASSERT_EQ(size
, 10ull<<20);
818 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 11, &pspec
, &size
));
819 ASSERT_EQ(pspec
.pool_id
, 1);
820 ASSERT_EQ(pspec
.image_id
, "parent");
821 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
822 ASSERT_EQ(size
, 5ull<<20);
824 ASSERT_EQ(0, remove_parent(&ioctx
, oid
));
825 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 12, "snap3"));
826 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 10, &pspec
, &size
));
827 ASSERT_EQ(pspec
.pool_id
, 1);
828 ASSERT_EQ(pspec
.image_id
, "parent");
829 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
830 ASSERT_EQ(size
, 10ull<<20);
831 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 11, &pspec
, &size
));
832 ASSERT_EQ(pspec
.pool_id
, 1);
833 ASSERT_EQ(pspec
.image_id
, "parent");
834 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
835 ASSERT_EQ(size
, 5ull<<20);
836 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 12, &pspec
, &size
));
837 ASSERT_EQ(-1, pspec
.pool_id
);
839 // make sure set_parent takes min of our size and parent's size
840 ASSERT_EQ(0, set_parent(&ioctx
, oid
, {1, "", "parent", 3}, 1<<20));
841 ASSERT_EQ(0, get_parent(&ioctx
, oid
, CEPH_NOSNAP
, &pspec
, &size
));
842 ASSERT_EQ(pspec
.pool_id
, 1);
843 ASSERT_EQ(pspec
.image_id
, "parent");
844 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
845 ASSERT_EQ(size
, 1ull<<20);
846 ASSERT_EQ(0, remove_parent(&ioctx
, oid
));
848 ASSERT_EQ(0, set_parent(&ioctx
, oid
, {1, "", "parent", 3}, 100<<20));
849 ASSERT_EQ(0, get_parent(&ioctx
, oid
, CEPH_NOSNAP
, &pspec
, &size
));
850 ASSERT_EQ(pspec
.pool_id
, 1);
851 ASSERT_EQ(pspec
.image_id
, "parent");
852 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
853 ASSERT_EQ(size
, 33ull<<20);
854 ASSERT_EQ(0, remove_parent(&ioctx
, oid
));
856 // make sure resize adjust parent overlap
857 ASSERT_EQ(0, set_parent(&ioctx
, oid
, {1, "", "parent", 3}, 10<<20));
859 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 14, "snap4"));
860 ASSERT_EQ(0, set_size(&ioctx
, oid
, 3 << 20));
861 ASSERT_EQ(0, get_parent(&ioctx
, oid
, CEPH_NOSNAP
, &pspec
, &size
));
862 ASSERT_EQ(pspec
.pool_id
, 1);
863 ASSERT_EQ(pspec
.image_id
, "parent");
864 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
865 ASSERT_EQ(size
, 3ull<<20);
866 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 14, &pspec
, &size
));
867 ASSERT_EQ(pspec
.pool_id
, 1);
868 ASSERT_EQ(pspec
.image_id
, "parent");
869 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
870 ASSERT_EQ(size
, 10ull<<20);
872 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 15, "snap5"));
873 ASSERT_EQ(0, set_size(&ioctx
, oid
, 30 << 20));
874 ASSERT_EQ(0, get_parent(&ioctx
, oid
, CEPH_NOSNAP
, &pspec
, &size
));
875 ASSERT_EQ(pspec
.pool_id
, 1);
876 ASSERT_EQ(pspec
.image_id
, "parent");
877 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
878 ASSERT_EQ(size
, 3ull<<20);
879 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 14, &pspec
, &size
));
880 ASSERT_EQ(pspec
.pool_id
, 1);
881 ASSERT_EQ(pspec
.image_id
, "parent");
882 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
883 ASSERT_EQ(size
, 10ull<<20);
884 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 15, &pspec
, &size
));
885 ASSERT_EQ(pspec
.pool_id
, 1);
886 ASSERT_EQ(pspec
.image_id
, "parent");
887 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
888 ASSERT_EQ(size
, 3ull<<20);
890 ASSERT_EQ(0, set_size(&ioctx
, oid
, 2 << 20));
891 ASSERT_EQ(0, get_parent(&ioctx
, oid
, CEPH_NOSNAP
, &pspec
, &size
));
892 ASSERT_EQ(pspec
.pool_id
, 1);
893 ASSERT_EQ(pspec
.image_id
, "parent");
894 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
895 ASSERT_EQ(size
, 2ull<<20);
897 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 16, "snap6"));
898 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 16, &pspec
, &size
));
899 ASSERT_EQ(pspec
.pool_id
, 1);
900 ASSERT_EQ(pspec
.image_id
, "parent");
901 ASSERT_EQ(pspec
.snap_id
, snapid_t(3));
902 ASSERT_EQ(size
, 2ull<<20);
904 ASSERT_EQ(0, ioctx
.remove(oid
));
905 ASSERT_EQ(0, create_image(&ioctx
, oid
, 33<<20, 22,
906 RBD_FEATURE_LAYERING
| RBD_FEATURE_DEEP_FLATTEN
,
908 ASSERT_EQ(0, set_parent(&ioctx
, oid
, {1, "", "parent", 3}, 100<<20));
909 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 1, "snap1"));
910 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 2, "snap2"));
911 ASSERT_EQ(0, remove_parent(&ioctx
, oid
));
913 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 1, &pspec
, &size
));
914 ASSERT_EQ(-1, pspec
.pool_id
);
915 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 2, &pspec
, &size
));
916 ASSERT_EQ(-1, pspec
.pool_id
);
917 ASSERT_EQ(0, get_parent(&ioctx
, oid
, CEPH_NOSNAP
, &pspec
, &size
));
918 ASSERT_EQ(-1, pspec
.pool_id
);
923 TEST_F(TestClsRbd
, parents_v2
)
925 librados::IoCtx ioctx
;
926 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
928 std::string oid
= get_temp_image_name();
929 cls::rbd::ParentImageSpec parent_image_spec
;
930 std::optional
<uint64_t> parent_overlap
;
932 ASSERT_EQ(-ENOENT
, parent_get(&ioctx
, oid
, &parent_image_spec
));
933 ASSERT_EQ(-ENOENT
, parent_overlap_get(&ioctx
, oid
, CEPH_NOSNAP
,
935 ASSERT_EQ(-ENOENT
, parent_attach(&ioctx
, oid
, parent_image_spec
, 0ULL,
937 ASSERT_EQ(-ENOENT
, parent_detach(&ioctx
, oid
));
939 // no layering support should fail
940 oid
= get_temp_image_name();
941 ASSERT_EQ(0, create_image(&ioctx
, oid
, 33<<20, 22, 0, "old_blk.", -1));
942 ASSERT_EQ(0, parent_get(&ioctx
, oid
, &parent_image_spec
));
943 ASSERT_FALSE(parent_image_spec
.exists());
944 ASSERT_EQ(0, parent_overlap_get(&ioctx
, oid
, CEPH_NOSNAP
, &parent_overlap
));
945 ASSERT_EQ(std::nullopt
, parent_overlap
);
946 ASSERT_EQ(-ENOEXEC
, parent_attach(&ioctx
, oid
, parent_image_spec
, 0ULL, false));
947 ASSERT_EQ(-ENOEXEC
, parent_detach(&ioctx
, oid
));
949 // layering support available -- no pool namespaces
950 oid
= get_temp_image_name();
951 ASSERT_EQ(0, create_image(&ioctx
, oid
, 33<<20, 22, RBD_FEATURE_LAYERING
,
954 ASSERT_EQ(0, parent_get(&ioctx
, oid
, &parent_image_spec
));
955 ASSERT_FALSE(parent_image_spec
.exists());
956 ASSERT_EQ(0, parent_overlap_get(&ioctx
, oid
, CEPH_NOSNAP
, &parent_overlap
));
957 ASSERT_EQ(std::nullopt
, parent_overlap
);
958 ASSERT_EQ(-EINVAL
, parent_attach(&ioctx
, oid
, parent_image_spec
, 0ULL, false));
959 ASSERT_EQ(-ENOENT
, parent_detach(&ioctx
, oid
));
961 parent_image_spec
= {1, "", "parent", 2};
962 parent_overlap
= (33 << 20) + 1;
963 ASSERT_EQ(0, parent_attach(&ioctx
, oid
, parent_image_spec
, *parent_overlap
,
965 ASSERT_EQ(-EEXIST
, parent_attach(&ioctx
, oid
, parent_image_spec
,
966 *parent_overlap
, false));
967 ASSERT_EQ(0, parent_attach(&ioctx
, oid
, parent_image_spec
, *parent_overlap
,
971 cls::rbd::ParentImageSpec on_disk_parent_image_spec
;
972 std::optional
<uint64_t> on_disk_parent_overlap
;
973 ASSERT_EQ(0, parent_get(&ioctx
, oid
, &on_disk_parent_image_spec
));
974 ASSERT_EQ(parent_image_spec
, on_disk_parent_image_spec
);
975 ASSERT_EQ(0, parent_overlap_get(&ioctx
, oid
, CEPH_NOSNAP
,
976 &on_disk_parent_overlap
));
977 ASSERT_EQ(parent_overlap
, on_disk_parent_overlap
);
979 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 10, "snap1"));
980 ASSERT_EQ(0, parent_overlap_get(&ioctx
, oid
, 10, &on_disk_parent_overlap
));
981 std::optional
<uint64_t> snap_1_parent_overlap
= parent_overlap
;
982 ASSERT_EQ(snap_1_parent_overlap
, on_disk_parent_overlap
);
984 parent_overlap
= (32 << 20);
985 ASSERT_EQ(0, set_size(&ioctx
, oid
, *parent_overlap
));
986 ASSERT_EQ(0, parent_overlap_get(&ioctx
, oid
, CEPH_NOSNAP
,
987 &on_disk_parent_overlap
));
988 ASSERT_EQ(parent_overlap
, on_disk_parent_overlap
);
990 ASSERT_EQ(0, parent_overlap_get(&ioctx
, oid
, 10, &on_disk_parent_overlap
));
991 ASSERT_EQ(snap_1_parent_overlap
, on_disk_parent_overlap
);
993 ASSERT_EQ(0, parent_detach(&ioctx
, oid
));
994 ASSERT_EQ(-ENOENT
, parent_detach(&ioctx
, oid
));
996 ASSERT_EQ(0, parent_get(&ioctx
, oid
, &on_disk_parent_image_spec
));
997 ASSERT_EQ(parent_image_spec
, on_disk_parent_image_spec
);
998 ASSERT_EQ(0, parent_overlap_get(&ioctx
, oid
, CEPH_NOSNAP
,
999 &on_disk_parent_overlap
));
1000 ASSERT_EQ(std::nullopt
, on_disk_parent_overlap
);
1002 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 10));
1003 ASSERT_EQ(0, parent_get(&ioctx
, oid
, &on_disk_parent_image_spec
));
1004 ASSERT_FALSE(on_disk_parent_image_spec
.exists());
1006 // clone across pool namespaces
1007 parent_image_spec
.pool_namespace
= "ns";
1008 parent_overlap
= 31 << 20;
1009 ASSERT_EQ(0, parent_attach(&ioctx
, oid
, parent_image_spec
, *parent_overlap
,
1011 ASSERT_EQ(-EEXIST
, parent_attach(&ioctx
, oid
, parent_image_spec
,
1012 *parent_overlap
, false));
1013 ASSERT_EQ(0, parent_attach(&ioctx
, oid
, parent_image_spec
, *parent_overlap
,
1016 ASSERT_EQ(0, parent_get(&ioctx
, oid
, &on_disk_parent_image_spec
));
1017 ASSERT_EQ(parent_image_spec
, on_disk_parent_image_spec
);
1018 ASSERT_EQ(0, parent_overlap_get(&ioctx
, oid
, CEPH_NOSNAP
,
1019 &on_disk_parent_overlap
));
1020 ASSERT_EQ(parent_overlap
, on_disk_parent_overlap
);
1022 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 10, "snap1"));
1023 ASSERT_EQ(0, parent_overlap_get(&ioctx
, oid
, 10, &on_disk_parent_overlap
));
1024 snap_1_parent_overlap
= parent_overlap
;
1025 ASSERT_EQ(snap_1_parent_overlap
, on_disk_parent_overlap
);
1027 parent_overlap
= (30 << 20);
1028 ASSERT_EQ(0, set_size(&ioctx
, oid
, *parent_overlap
));
1029 ASSERT_EQ(0, parent_overlap_get(&ioctx
, oid
, CEPH_NOSNAP
,
1030 &on_disk_parent_overlap
));
1031 ASSERT_EQ(parent_overlap
, on_disk_parent_overlap
);
1033 ASSERT_EQ(0, parent_overlap_get(&ioctx
, oid
, 10, &on_disk_parent_overlap
));
1034 ASSERT_EQ(snap_1_parent_overlap
, on_disk_parent_overlap
);
1036 ASSERT_EQ(-EXDEV
, remove_parent(&ioctx
, oid
));
1037 ASSERT_EQ(0, parent_detach(&ioctx
, oid
));
1038 ASSERT_EQ(-ENOENT
, parent_detach(&ioctx
, oid
));
1040 cls::rbd::ParentImageSpec on_disk_parent_spec
;
1041 uint64_t legacy_parent_overlap
;
1042 ASSERT_EQ(-EXDEV
, get_parent(&ioctx
, oid
, CEPH_NOSNAP
, &on_disk_parent_spec
,
1043 &legacy_parent_overlap
));
1044 ASSERT_EQ(-EXDEV
, get_parent(&ioctx
, oid
, 10, &on_disk_parent_spec
,
1045 &legacy_parent_overlap
));
1047 ASSERT_EQ(0, parent_get(&ioctx
, oid
, &on_disk_parent_image_spec
));
1048 ASSERT_EQ(parent_image_spec
, on_disk_parent_image_spec
);
1049 ASSERT_EQ(0, parent_overlap_get(&ioctx
, oid
, CEPH_NOSNAP
,
1050 &on_disk_parent_overlap
));
1051 ASSERT_EQ(std::nullopt
, on_disk_parent_overlap
);
1053 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 10));
1054 ASSERT_EQ(0, parent_get(&ioctx
, oid
, &on_disk_parent_image_spec
));
1055 ASSERT_FALSE(on_disk_parent_image_spec
.exists());
1058 TEST_F(TestClsRbd
, snapshots
)
1060 cls::rbd::SnapshotNamespace userSnapNamespace
= cls::rbd::UserSnapshotNamespace();
1061 librados::IoCtx ioctx
;
1062 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1064 string oid
= get_temp_image_name();
1065 ASSERT_EQ(-ENOENT
, snapshot_add(&ioctx
, oid
, 0, "snap1"));
1067 ASSERT_EQ(0, create_image(&ioctx
, oid
, 10, 22, 0, oid
, -1));
1070 cls::rbd::SnapshotInfo snap
;
1071 std::string snap_name
;
1074 ParentImageInfo parent
;
1075 uint8_t protection_status
;
1076 utime_t snap_timestamp
;
1078 ASSERT_EQ(0, get_snapcontext(&ioctx
, oid
, &snapc
));
1079 ASSERT_EQ(0u, snapc
.snaps
.size());
1080 ASSERT_EQ(0u, snapc
.seq
);
1082 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 0, "snap1"));
1083 ASSERT_EQ(0, get_snapcontext(&ioctx
, oid
, &snapc
));
1084 ASSERT_EQ(1u, snapc
.snaps
.size());
1085 ASSERT_EQ(0u, snapc
.snaps
[0]);
1086 ASSERT_EQ(0u, snapc
.seq
);
1088 ASSERT_EQ(0, snapshot_get(&ioctx
, oid
, 0, &snap
));
1089 ASSERT_EQ("snap1", snap
.name
);
1090 ASSERT_EQ(userSnapNamespace
, snap
.snapshot_namespace
);
1091 ASSERT_EQ(0, get_snapshot_name(&ioctx
, oid
, 0, &snap_name
));
1092 ASSERT_EQ("snap1", snap_name
);
1093 ASSERT_EQ(0, get_size(&ioctx
, oid
, 0, &snap_size
, &snap_order
));
1094 ASSERT_EQ(10U, snap_size
);
1095 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 0, &parent
.spec
, &parent
.overlap
));
1096 ASSERT_EQ(0, get_protection_status(&ioctx
, oid
, 0, &protection_status
));
1097 ASSERT_EQ(0, get_snapshot_timestamp(&ioctx
, oid
, 0, &snap_timestamp
));
1099 // snap with same id and name
1100 ASSERT_EQ(-EEXIST
, snapshot_add(&ioctx
, oid
, 0, "snap1"));
1101 ASSERT_EQ(0, get_snapcontext(&ioctx
, oid
, &snapc
));
1102 ASSERT_EQ(1u, snapc
.snaps
.size());
1103 ASSERT_EQ(0u, snapc
.snaps
[0]);
1104 ASSERT_EQ(0u, snapc
.seq
);
1106 // snap with same id, different name
1107 ASSERT_EQ(-EEXIST
, snapshot_add(&ioctx
, oid
, 0, "snap2"));
1108 ASSERT_EQ(0, get_snapcontext(&ioctx
, oid
, &snapc
));
1109 ASSERT_EQ(1u, snapc
.snaps
.size());
1110 ASSERT_EQ(0u, snapc
.snaps
[0]);
1111 ASSERT_EQ(0u, snapc
.seq
);
1113 // snap with different id, same name
1114 ASSERT_EQ(-EEXIST
, snapshot_add(&ioctx
, oid
, 1, "snap1"));
1115 ASSERT_EQ(0, get_snapcontext(&ioctx
, oid
, &snapc
));
1116 ASSERT_EQ(1u, snapc
.snaps
.size());
1117 ASSERT_EQ(0u, snapc
.snaps
[0]);
1118 ASSERT_EQ(0u, snapc
.seq
);
1120 // snap with different id, different name
1121 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 1, "snap2"));
1122 ASSERT_EQ(0, get_snapcontext(&ioctx
, oid
, &snapc
));
1123 ASSERT_EQ(2u, snapc
.snaps
.size());
1124 ASSERT_EQ(1u, snapc
.snaps
[0]);
1125 ASSERT_EQ(0u, snapc
.snaps
[1]);
1126 ASSERT_EQ(1u, snapc
.seq
);
1128 // snap id less than current snap seq
1129 ASSERT_EQ(-ESTALE
, snapshot_add(&ioctx
, oid
, 0, "snap3"));
1131 ASSERT_EQ(0, snapshot_get(&ioctx
, oid
, 1, &snap
));
1132 ASSERT_EQ("snap2", snap
.name
);
1133 ASSERT_EQ(userSnapNamespace
, snap
.snapshot_namespace
);
1134 ASSERT_EQ(0, get_snapshot_name(&ioctx
, oid
, 1, &snap_name
));
1135 ASSERT_EQ("snap2", snap_name
);
1136 ASSERT_EQ(0, get_size(&ioctx
, oid
, 1, &snap_size
, &snap_order
));
1137 ASSERT_EQ(10U, snap_size
);
1138 ASSERT_EQ(0, get_parent(&ioctx
, oid
, 1, &parent
.spec
, &parent
.overlap
));
1139 ASSERT_EQ(0, get_protection_status(&ioctx
, oid
, 1, &protection_status
));
1140 ASSERT_EQ(0, get_snapshot_timestamp(&ioctx
, oid
, 1, &snap_timestamp
));
1142 ASSERT_EQ(0, snapshot_rename(&ioctx
, oid
, 0, "snap1-rename"));
1143 ASSERT_EQ(0, snapshot_get(&ioctx
, oid
, 0, &snap
));
1144 ASSERT_EQ("snap1-rename", snap
.name
);
1145 ASSERT_EQ(0, get_snapshot_name(&ioctx
, oid
, 0, &snap_name
));
1146 ASSERT_EQ("snap1-rename", snap_name
);
1148 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 0));
1149 ASSERT_EQ(0, get_snapcontext(&ioctx
, oid
, &snapc
));
1150 ASSERT_EQ(1u, snapc
.snaps
.size());
1151 ASSERT_EQ(1u, snapc
.snaps
[0]);
1152 ASSERT_EQ(1u, snapc
.seq
);
1156 ASSERT_EQ(0, set_size(&ioctx
, oid
, 0));
1157 ASSERT_EQ(0, get_size(&ioctx
, oid
, CEPH_NOSNAP
, &size
, &order
));
1158 ASSERT_EQ(0u, size
);
1159 ASSERT_EQ(22u, order
);
1161 uint64_t large_snap_id
= 1ull << 63;
1162 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, large_snap_id
, "snap3"));
1163 ASSERT_EQ(0, get_snapcontext(&ioctx
, oid
, &snapc
));
1164 ASSERT_EQ(2u, snapc
.snaps
.size());
1165 ASSERT_EQ(large_snap_id
, snapc
.snaps
[0]);
1166 ASSERT_EQ(1u, snapc
.snaps
[1]);
1167 ASSERT_EQ(large_snap_id
, snapc
.seq
);
1169 ASSERT_EQ(0, snapshot_get(&ioctx
, oid
, large_snap_id
, &snap
));
1170 ASSERT_EQ("snap3", snap
.name
);
1171 ASSERT_EQ(0, get_snapshot_name(&ioctx
, oid
, large_snap_id
, &snap_name
));
1172 ASSERT_EQ("snap3", snap_name
);
1173 ASSERT_EQ(0, get_size(&ioctx
, oid
, large_snap_id
, &snap_size
, &snap_order
));
1174 ASSERT_EQ(0U, snap_size
);
1175 ASSERT_EQ(22u, snap_order
);
1177 ASSERT_EQ(0, get_size(&ioctx
, oid
, 1, &snap_size
, &snap_order
));
1178 ASSERT_EQ(10u, snap_size
);
1179 ASSERT_EQ(22u, snap_order
);
1181 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, large_snap_id
));
1182 ASSERT_EQ(0, get_snapcontext(&ioctx
, oid
, &snapc
));
1183 ASSERT_EQ(1u, snapc
.snaps
.size());
1184 ASSERT_EQ(1u, snapc
.snaps
[0]);
1185 ASSERT_EQ(large_snap_id
, snapc
.seq
);
1187 ASSERT_EQ(-ENOENT
, snapshot_remove(&ioctx
, oid
, large_snap_id
));
1188 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 1));
1189 ASSERT_EQ(0, get_snapcontext(&ioctx
, oid
, &snapc
));
1190 ASSERT_EQ(0u, snapc
.snaps
.size());
1191 ASSERT_EQ(large_snap_id
, snapc
.seq
);
1195 TEST_F(TestClsRbd
, snapid_race
)
1197 librados::IoCtx ioctx
;
1198 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1201 buffer::ptr
bp(4096);
1205 string oid
= get_temp_image_name();
1206 ASSERT_EQ(0, ioctx
.write(oid
, bl
, 4096, 0));
1207 ASSERT_EQ(0, old_snapshot_add(&ioctx
, oid
, 1, "test1"));
1208 ASSERT_EQ(0, old_snapshot_add(&ioctx
, oid
, 3, "test3"));
1209 ASSERT_EQ(-ESTALE
, old_snapshot_add(&ioctx
, oid
, 2, "test2"));
1214 TEST_F(TestClsRbd
, stripingv2
)
1216 librados::IoCtx ioctx
;
1217 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1219 string oid
= get_temp_image_name();
1220 string oid2
= get_temp_image_name();
1221 ASSERT_EQ(0, create_image(&ioctx
, oid
, 10, 22, 0, oid
, -1));
1223 uint64_t su
= 65536, sc
= 12;
1224 ASSERT_EQ(-ENOEXEC
, get_stripe_unit_count(&ioctx
, oid
, &su
, &sc
));
1225 ASSERT_EQ(-ENOEXEC
, set_stripe_unit_count(&ioctx
, oid
, su
, sc
));
1227 ASSERT_EQ(0, create_image(&ioctx
, oid2
, 10, 22, RBD_FEATURE_STRIPINGV2
,
1229 ASSERT_EQ(0, get_stripe_unit_count(&ioctx
, oid2
, &su
, &sc
));
1230 ASSERT_EQ(1ull << 22, su
);
1231 ASSERT_EQ(1ull, sc
);
1234 ASSERT_EQ(0, set_stripe_unit_count(&ioctx
, oid2
, su
, sc
));
1236 ASSERT_EQ(0, get_stripe_unit_count(&ioctx
, oid2
, &su
, &sc
));
1237 ASSERT_EQ(8192ull, su
);
1238 ASSERT_EQ(456ull, sc
);
1240 // su must not be larger than an object
1241 ASSERT_EQ(-EINVAL
, set_stripe_unit_count(&ioctx
, oid2
, 1 << 23, 1));
1242 // su must be a factor of object size
1243 ASSERT_EQ(-EINVAL
, set_stripe_unit_count(&ioctx
, oid2
, 511, 1));
1244 // su and sc must be non-zero
1245 ASSERT_EQ(-EINVAL
, set_stripe_unit_count(&ioctx
, oid2
, 0, 1));
1246 ASSERT_EQ(-EINVAL
, set_stripe_unit_count(&ioctx
, oid2
, 1, 0));
1247 ASSERT_EQ(-EINVAL
, set_stripe_unit_count(&ioctx
, oid2
, 0, 0));
1252 TEST_F(TestClsRbd
, object_map_save
)
1254 librados::IoCtx ioctx
;
1255 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1257 string oid
= get_temp_image_name();
1258 BitVector
<2> ref_bit_vector
;
1259 ref_bit_vector
.resize(32);
1260 for (uint64_t i
= 0; i
< ref_bit_vector
.size(); ++i
) {
1261 ref_bit_vector
[i
] = 1;
1264 librados::ObjectWriteOperation op
;
1265 object_map_save(&op
, ref_bit_vector
);
1266 ASSERT_EQ(0, ioctx
.operate(oid
, &op
));
1268 BitVector
<2> osd_bit_vector
;
1269 ASSERT_EQ(0, object_map_load(&ioctx
, oid
, &osd_bit_vector
));
1270 ASSERT_EQ(ref_bit_vector
, osd_bit_vector
);
1273 TEST_F(TestClsRbd
, object_map_resize
)
1275 librados::IoCtx ioctx
;
1276 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1278 string oid
= get_temp_image_name();
1279 BitVector
<2> ref_bit_vector
;
1280 ref_bit_vector
.resize(32);
1281 for (uint64_t i
= 0; i
< ref_bit_vector
.size(); ++i
) {
1282 ref_bit_vector
[i
] = 1;
1285 librados::ObjectWriteOperation op1
;
1286 object_map_resize(&op1
, ref_bit_vector
.size(), 1);
1287 ASSERT_EQ(0, ioctx
.operate(oid
, &op1
));
1289 BitVector
<2> osd_bit_vector
;
1290 ASSERT_EQ(0, object_map_load(&ioctx
, oid
, &osd_bit_vector
));
1291 ASSERT_EQ(ref_bit_vector
, osd_bit_vector
);
1293 ref_bit_vector
.resize(64);
1294 for (uint64_t i
= 32; i
< ref_bit_vector
.size(); ++i
) {
1295 ref_bit_vector
[i
] = 2;
1298 librados::ObjectWriteOperation op2
;
1299 object_map_resize(&op2
, ref_bit_vector
.size(), 2);
1300 ASSERT_EQ(0, ioctx
.operate(oid
, &op2
));
1301 ASSERT_EQ(0, object_map_load(&ioctx
, oid
, &osd_bit_vector
));
1302 ASSERT_EQ(ref_bit_vector
, osd_bit_vector
);
1304 ref_bit_vector
.resize(32);
1306 librados::ObjectWriteOperation op3
;
1307 object_map_resize(&op3
, ref_bit_vector
.size(), 1);
1308 ASSERT_EQ(-ESTALE
, ioctx
.operate(oid
, &op3
));
1310 librados::ObjectWriteOperation op4
;
1311 object_map_resize(&op4
, ref_bit_vector
.size(), 2);
1312 ASSERT_EQ(0, ioctx
.operate(oid
, &op4
));
1314 ASSERT_EQ(0, object_map_load(&ioctx
, oid
, &osd_bit_vector
));
1315 ASSERT_EQ(ref_bit_vector
, osd_bit_vector
);
1320 TEST_F(TestClsRbd
, object_map_update
)
1322 librados::IoCtx ioctx
;
1323 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1325 string oid
= get_temp_image_name();
1326 BitVector
<2> ref_bit_vector
;
1327 ref_bit_vector
.resize(16);
1328 for (uint64_t i
= 0; i
< ref_bit_vector
.size(); ++i
) {
1329 ref_bit_vector
[i
] = 2;
1332 BitVector
<2> osd_bit_vector
;
1334 librados::ObjectWriteOperation op1
;
1335 object_map_resize(&op1
, ref_bit_vector
.size(), 2);
1336 ASSERT_EQ(0, ioctx
.operate(oid
, &op1
));
1337 ASSERT_EQ(0, object_map_load(&ioctx
, oid
, &osd_bit_vector
));
1338 ASSERT_EQ(ref_bit_vector
, osd_bit_vector
);
1340 ref_bit_vector
[7] = 1;
1341 ref_bit_vector
[8] = 1;
1343 librados::ObjectWriteOperation op2
;
1344 object_map_update(&op2
, 7, 9, 1, boost::optional
<uint8_t>());
1345 ASSERT_EQ(0, ioctx
.operate(oid
, &op2
));
1346 ASSERT_EQ(0, object_map_load(&ioctx
, oid
, &osd_bit_vector
));
1347 ASSERT_EQ(ref_bit_vector
, osd_bit_vector
);
1349 ref_bit_vector
[7] = 3;
1350 ref_bit_vector
[8] = 3;
1352 librados::ObjectWriteOperation op3
;
1353 object_map_update(&op3
, 6, 10, 3, 1);
1354 ASSERT_EQ(0, ioctx
.operate(oid
, &op3
));
1355 ASSERT_EQ(0, object_map_load(&ioctx
, oid
, &osd_bit_vector
));
1356 ASSERT_EQ(ref_bit_vector
, osd_bit_vector
);
1361 TEST_F(TestClsRbd
, object_map_load_enoent
)
1363 librados::IoCtx ioctx
;
1364 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1366 string oid
= get_temp_image_name();
1367 BitVector
<2> osd_bit_vector
;
1368 ASSERT_EQ(-ENOENT
, object_map_load(&ioctx
, oid
, &osd_bit_vector
));
1373 TEST_F(TestClsRbd
, object_map_snap_add
)
1375 librados::IoCtx ioctx
;
1376 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1378 string oid
= get_temp_image_name();
1379 BitVector
<2> ref_bit_vector
;
1380 ref_bit_vector
.resize(16);
1381 for (uint64_t i
= 0; i
< ref_bit_vector
.size(); ++i
) {
1383 ref_bit_vector
[i
] = OBJECT_NONEXISTENT
;
1385 ref_bit_vector
[i
] = OBJECT_EXISTS
;
1389 BitVector
<2> osd_bit_vector
;
1391 librados::ObjectWriteOperation op1
;
1392 object_map_resize(&op1
, ref_bit_vector
.size(), OBJECT_EXISTS
);
1393 ASSERT_EQ(0, ioctx
.operate(oid
, &op1
));
1395 librados::ObjectWriteOperation op2
;
1396 object_map_update(&op2
, 0, 4, OBJECT_NONEXISTENT
, boost::optional
<uint8_t>());
1397 ASSERT_EQ(0, ioctx
.operate(oid
, &op2
));
1399 ASSERT_EQ(0, object_map_load(&ioctx
, oid
, &osd_bit_vector
));
1400 ASSERT_EQ(ref_bit_vector
, osd_bit_vector
);
1402 librados::ObjectWriteOperation op3
;
1403 object_map_snap_add(&op3
);
1404 ASSERT_EQ(0, ioctx
.operate(oid
, &op3
));
1406 for (uint64_t i
= 0; i
< ref_bit_vector
.size(); ++i
) {
1407 if (ref_bit_vector
[i
] == OBJECT_EXISTS
) {
1408 ref_bit_vector
[i
] = OBJECT_EXISTS_CLEAN
;
1412 ASSERT_EQ(0, object_map_load(&ioctx
, oid
, &osd_bit_vector
));
1413 ASSERT_EQ(ref_bit_vector
, osd_bit_vector
);
1416 TEST_F(TestClsRbd
, object_map_snap_remove
)
1418 librados::IoCtx ioctx
;
1419 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1421 string oid
= get_temp_image_name();
1422 BitVector
<2> ref_bit_vector
;
1423 ref_bit_vector
.resize(16);
1424 for (uint64_t i
= 0; i
< ref_bit_vector
.size(); ++i
) {
1426 ref_bit_vector
[i
] = OBJECT_EXISTS_CLEAN
;
1428 ref_bit_vector
[i
] = OBJECT_EXISTS
;
1432 BitVector
<2> osd_bit_vector
;
1434 librados::ObjectWriteOperation op1
;
1435 object_map_resize(&op1
, ref_bit_vector
.size(), OBJECT_EXISTS
);
1436 ASSERT_EQ(0, ioctx
.operate(oid
, &op1
));
1438 librados::ObjectWriteOperation op2
;
1439 object_map_update(&op2
, 0, 4, OBJECT_EXISTS_CLEAN
, boost::optional
<uint8_t>());
1440 ASSERT_EQ(0, ioctx
.operate(oid
, &op2
));
1442 ASSERT_EQ(0, object_map_load(&ioctx
, oid
, &osd_bit_vector
));
1443 ASSERT_EQ(ref_bit_vector
, osd_bit_vector
);
1445 BitVector
<2> snap_bit_vector
;
1446 snap_bit_vector
.resize(4);
1447 for (uint64_t i
= 0; i
< snap_bit_vector
.size(); ++i
) {
1448 if (i
== 1 || i
== 2) {
1449 snap_bit_vector
[i
] = OBJECT_EXISTS
;
1451 snap_bit_vector
[i
] = OBJECT_NONEXISTENT
;
1455 librados::ObjectWriteOperation op3
;
1456 object_map_snap_remove(&op3
, snap_bit_vector
);
1457 ASSERT_EQ(0, ioctx
.operate(oid
, &op3
));
1459 ref_bit_vector
[1] = OBJECT_EXISTS
;
1460 ref_bit_vector
[2] = OBJECT_EXISTS
;
1461 ASSERT_EQ(0, object_map_load(&ioctx
, oid
, &osd_bit_vector
));
1462 ASSERT_EQ(ref_bit_vector
, osd_bit_vector
);
1465 TEST_F(TestClsRbd
, flags
)
1467 librados::IoCtx ioctx
;
1468 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1470 string oid
= get_temp_image_name();
1471 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
1474 ASSERT_EQ(0, get_flags(&ioctx
, oid
, CEPH_NOSNAP
, &flags
));
1475 ASSERT_EQ(0U, flags
);
1477 librados::ObjectWriteOperation op1
;
1478 set_flags(&op1
, CEPH_NOSNAP
, 3, 2);
1479 ASSERT_EQ(0, ioctx
.operate(oid
, &op1
));
1480 ASSERT_EQ(0, get_flags(&ioctx
, oid
, CEPH_NOSNAP
, &flags
));
1481 ASSERT_EQ(2U, flags
);
1483 uint64_t snap_id
= 10;
1484 ASSERT_EQ(-ENOENT
, get_flags(&ioctx
, oid
, snap_id
, &flags
));
1485 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, snap_id
, "snap"));
1487 librados::ObjectWriteOperation op2
;
1488 set_flags(&op2
, snap_id
, 31, 4);
1489 ASSERT_EQ(0, ioctx
.operate(oid
, &op2
));
1490 ASSERT_EQ(0, get_flags(&ioctx
, oid
, snap_id
, &flags
));
1491 ASSERT_EQ(6U, flags
);
1496 TEST_F(TestClsRbd
, metadata
)
1498 librados::IoCtx ioctx
;
1499 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1501 string oid
= get_temp_image_name();
1502 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
1504 map
<string
, bufferlist
> pairs
;
1506 ASSERT_EQ(0, metadata_list(&ioctx
, oid
, "", 0, &pairs
));
1507 ASSERT_TRUE(pairs
.empty());
1509 pairs
["key1"].append("value1");
1510 pairs
["key2"].append("value2");
1511 ASSERT_EQ(0, metadata_set(&ioctx
, oid
, pairs
));
1512 ASSERT_EQ(0, metadata_get(&ioctx
, oid
, "key1", &value
));
1513 ASSERT_EQ(0, strcmp("value1", value
.c_str()));
1515 ASSERT_EQ(0, metadata_list(&ioctx
, oid
, "", 0, &pairs
));
1516 ASSERT_EQ(2U, pairs
.size());
1517 ASSERT_EQ(0, strncmp("value1", pairs
["key1"].c_str(), 6));
1518 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
1521 ASSERT_EQ(0, metadata_remove(&ioctx
, oid
, "key1"));
1522 ASSERT_EQ(0, metadata_remove(&ioctx
, oid
, "key3"));
1523 ASSERT_TRUE(metadata_get(&ioctx
, oid
, "key1", &value
) < 0);
1524 ASSERT_EQ(0, metadata_list(&ioctx
, oid
, "", 0, &pairs
));
1525 ASSERT_EQ(1U, pairs
.size());
1526 ASSERT_EQ(0, strncmp("value2", pairs
["key2"].c_str(), 6));
1529 char key
[10], val
[20];
1530 for (int i
= 0; i
< 1024; i
++) {
1531 sprintf(key
, "key%d", i
);
1532 sprintf(val
, "value%d", i
);
1533 pairs
[key
].append(val
, strlen(val
));
1535 ASSERT_EQ(0, metadata_set(&ioctx
, oid
, pairs
));
1537 string last_read
= "";
1538 uint64_t max_read
= 48, r
;
1540 map
<string
, bufferlist
> data
;
1542 map
<string
, bufferlist
> cur
;
1543 metadata_list(&ioctx
, oid
, last_read
, max_read
, &cur
);
1545 for (map
<string
, bufferlist
>::iterator it
= cur
.begin();
1546 it
!= cur
.end(); ++it
)
1547 data
[it
->first
] = it
->second
;
1548 last_read
= cur
.rbegin()->first
;
1550 } while (r
== max_read
);
1551 ASSERT_EQ(size
, 1024U);
1552 for (map
<string
, bufferlist
>::iterator it
= data
.begin();
1553 it
!= data
.end(); ++it
) {
1554 ASSERT_TRUE(it
->second
.contents_equal(pairs
[it
->first
]));
1560 TEST_F(TestClsRbd
, set_features
)
1562 librados::IoCtx ioctx
;
1563 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1565 string oid
= get_temp_image_name();
1566 uint64_t base_features
= RBD_FEATURE_LAYERING
| RBD_FEATURE_DEEP_FLATTEN
;
1567 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, base_features
, oid
, -1));
1569 uint64_t features
= RBD_FEATURES_MUTABLE
;
1570 uint64_t mask
= RBD_FEATURES_MUTABLE
;
1571 ASSERT_EQ(0, set_features(&ioctx
, oid
, features
, mask
));
1573 uint64_t actual_features
;
1574 uint64_t incompatible_features
;
1575 ASSERT_EQ(0, get_features(&ioctx
, oid
, true, &actual_features
,
1576 &incompatible_features
));
1578 uint64_t expected_features
= RBD_FEATURES_MUTABLE
| base_features
;
1579 ASSERT_EQ(expected_features
, actual_features
);
1582 mask
= RBD_FEATURE_OBJECT_MAP
;
1583 ASSERT_EQ(0, set_features(&ioctx
, oid
, features
, mask
));
1585 ASSERT_EQ(0, get_features(&ioctx
, oid
, true, &actual_features
,
1586 &incompatible_features
));
1588 expected_features
= (RBD_FEATURES_MUTABLE
| base_features
) &
1589 ~RBD_FEATURE_OBJECT_MAP
;
1590 ASSERT_EQ(expected_features
, actual_features
);
1592 ASSERT_EQ(0, set_features(&ioctx
, oid
, 0, RBD_FEATURE_DEEP_FLATTEN
));
1593 ASSERT_EQ(-EINVAL
, set_features(&ioctx
, oid
, RBD_FEATURE_DEEP_FLATTEN
,
1594 RBD_FEATURE_DEEP_FLATTEN
));
1596 ASSERT_EQ(-EINVAL
, set_features(&ioctx
, oid
, 0, RBD_FEATURE_LAYERING
));
1597 ASSERT_EQ(-EINVAL
, set_features(&ioctx
, oid
, 0, RBD_FEATURE_OPERATIONS
));
1600 TEST_F(TestClsRbd
, mirror
) {
1601 librados::IoCtx ioctx
;
1602 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1603 ioctx
.remove(RBD_MIRRORING
);
1605 std::vector
<cls::rbd::MirrorPeer
> peers
;
1606 ASSERT_EQ(-ENOENT
, mirror_peer_list(&ioctx
, &peers
));
1609 ASSERT_EQ(-ENOENT
, mirror_uuid_get(&ioctx
, &uuid
));
1610 ASSERT_EQ(-EINVAL
, mirror_peer_add(&ioctx
, {"uuid1", MIRROR_PEER_DIRECTION_RX
,
1613 ASSERT_EQ(-EINVAL
, mirror_peer_ping(&ioctx
, "siteA", "mirror uuid"));
1615 cls::rbd::MirrorMode mirror_mode
;
1616 ASSERT_EQ(0, mirror_mode_get(&ioctx
, &mirror_mode
));
1617 ASSERT_EQ(cls::rbd::MIRROR_MODE_DISABLED
, mirror_mode
);
1619 ASSERT_EQ(-EINVAL
, mirror_mode_set(&ioctx
, cls::rbd::MIRROR_MODE_IMAGE
));
1620 ASSERT_EQ(-EINVAL
, mirror_uuid_set(&ioctx
, ""));
1621 ASSERT_EQ(0, mirror_uuid_set(&ioctx
, "mirror-uuid"));
1622 ASSERT_EQ(0, mirror_uuid_get(&ioctx
, &uuid
));
1623 ASSERT_EQ("mirror-uuid", uuid
);
1625 ASSERT_EQ(0, mirror_mode_set(&ioctx
, cls::rbd::MIRROR_MODE_IMAGE
));
1626 ASSERT_EQ(0, mirror_mode_get(&ioctx
, &mirror_mode
));
1627 ASSERT_EQ(cls::rbd::MIRROR_MODE_IMAGE
, mirror_mode
);
1629 ASSERT_EQ(-EINVAL
, mirror_uuid_set(&ioctx
, "new-mirror-uuid"));
1631 ASSERT_EQ(0, mirror_mode_set(&ioctx
, cls::rbd::MIRROR_MODE_POOL
));
1632 ASSERT_EQ(0, mirror_mode_get(&ioctx
, &mirror_mode
));
1633 ASSERT_EQ(cls::rbd::MIRROR_MODE_POOL
, mirror_mode
);
1635 ASSERT_EQ(-EINVAL
, mirror_peer_add(&ioctx
, {"mirror-uuid",
1636 MIRROR_PEER_DIRECTION_RX
, "siteA",
1638 ASSERT_EQ(-EINVAL
, mirror_peer_add(&ioctx
, {"uuid1", MIRROR_PEER_DIRECTION_TX
,
1641 ASSERT_EQ(0, mirror_peer_add(&ioctx
, {"uuid1", MIRROR_PEER_DIRECTION_RX
,
1642 "siteA", "client", "fsidA"}));
1643 ASSERT_EQ(0, mirror_peer_add(&ioctx
, {"uuid2", MIRROR_PEER_DIRECTION_RX
,
1644 "siteB", "admin", ""}));
1645 ASSERT_EQ(-ESTALE
, mirror_peer_add(&ioctx
, {"uuid2", MIRROR_PEER_DIRECTION_RX
,
1646 "siteC", "foo", ""}));
1647 ASSERT_EQ(-EEXIST
, mirror_peer_add(&ioctx
, {"uuid3", MIRROR_PEER_DIRECTION_RX
,
1648 "siteA", "foo", ""}));
1649 ASSERT_EQ(-EEXIST
, mirror_peer_add(&ioctx
, {"uuid3", MIRROR_PEER_DIRECTION_RX
,
1650 "siteC", "client", "fsidA"}));
1651 ASSERT_EQ(0, mirror_peer_add(&ioctx
, {"uuid3", MIRROR_PEER_DIRECTION_RX
,
1652 "siteC", "admin", ""}));
1653 ASSERT_EQ(0, mirror_peer_add(&ioctx
, {"uuid4", MIRROR_PEER_DIRECTION_RX
,
1654 "siteD", "admin", ""}));
1656 ASSERT_EQ(0, mirror_peer_list(&ioctx
, &peers
));
1657 std::vector
<cls::rbd::MirrorPeer
> expected_peers
= {
1658 {"uuid1", MIRROR_PEER_DIRECTION_RX
, "siteA", "client", "fsidA"},
1659 {"uuid2", MIRROR_PEER_DIRECTION_RX
, "siteB", "admin", ""},
1660 {"uuid3", MIRROR_PEER_DIRECTION_RX
, "siteC", "admin", ""},
1661 {"uuid4", MIRROR_PEER_DIRECTION_RX
, "siteD", "admin", ""}};
1662 ASSERT_EQ(expected_peers
, peers
);
1664 ASSERT_EQ(0, mirror_peer_remove(&ioctx
, "uuid5"));
1665 ASSERT_EQ(0, mirror_peer_remove(&ioctx
, "uuid4"));
1666 ASSERT_EQ(0, mirror_peer_remove(&ioctx
, "uuid2"));
1668 ASSERT_EQ(0, mirror_peer_list(&ioctx
, &peers
));
1670 {"uuid1", MIRROR_PEER_DIRECTION_RX
, "siteA", "client", "fsidA"},
1671 {"uuid3", MIRROR_PEER_DIRECTION_RX
, "siteC", "admin", ""}};
1672 ASSERT_EQ(expected_peers
, peers
);
1674 ASSERT_EQ(-ENOENT
, mirror_peer_set_client(&ioctx
, "uuid4", "new client"));
1675 ASSERT_EQ(0, mirror_peer_set_client(&ioctx
, "uuid1", "new client"));
1677 ASSERT_EQ(-ENOENT
, mirror_peer_set_cluster(&ioctx
, "uuid4", "new site"));
1678 ASSERT_EQ(0, mirror_peer_set_cluster(&ioctx
, "uuid3", "new site"));
1680 ASSERT_EQ(0, mirror_peer_list(&ioctx
, &peers
));
1682 {"uuid1", MIRROR_PEER_DIRECTION_RX
, "siteA", "new client", "fsidA"},
1683 {"uuid3", MIRROR_PEER_DIRECTION_RX
, "new site", "admin", ""}};
1684 ASSERT_EQ(expected_peers
, peers
);
1686 ASSERT_EQ(0, mirror_peer_remove(&ioctx
, "uuid1"));
1688 ASSERT_EQ(0, mirror_peer_list(&ioctx
, &peers
));
1690 {"uuid3", MIRROR_PEER_DIRECTION_RX
, "new site", "admin", ""}};
1691 ASSERT_EQ(expected_peers
, peers
);
1693 ASSERT_EQ(-EINVAL
, mirror_peer_ping(&ioctx
, "", "mirror uuid"));
1694 ASSERT_EQ(-EINVAL
, mirror_peer_ping(&ioctx
, "new site", ""));
1695 ASSERT_EQ(0, mirror_peer_ping(&ioctx
, "new site", "mirror uuid"));
1697 ASSERT_EQ(0, mirror_peer_list(&ioctx
, &peers
));
1698 ASSERT_EQ(1U, peers
.size());
1699 ASSERT_LT(utime_t
{}, peers
[0].last_seen
);
1701 {"uuid3", MIRROR_PEER_DIRECTION_RX_TX
, "new site", "admin", "mirror uuid"}};
1702 expected_peers
[0].last_seen
= peers
[0].last_seen
;
1703 ASSERT_EQ(expected_peers
, peers
);
1704 ASSERT_EQ(0, mirror_peer_remove(&ioctx
, "uuid3"));
1706 ASSERT_EQ(0, mirror_peer_ping(&ioctx
, "siteA", "mirror uuid"));
1708 ASSERT_EQ(0, mirror_peer_list(&ioctx
, &peers
));
1709 ASSERT_EQ(1U, peers
.size());
1710 ASSERT_FALSE(peers
[0].uuid
.empty());
1711 ASSERT_LT(utime_t
{}, peers
[0].last_seen
);
1713 {peers
[0].uuid
, MIRROR_PEER_DIRECTION_TX
, "siteA", "", "mirror uuid"}};
1714 expected_peers
[0].last_seen
= peers
[0].last_seen
;
1715 ASSERT_EQ(expected_peers
, peers
);
1717 ASSERT_EQ(-EBUSY
, mirror_mode_set(&ioctx
, cls::rbd::MIRROR_MODE_DISABLED
));
1718 ASSERT_EQ(0, mirror_peer_remove(&ioctx
, peers
[0].uuid
));
1720 ASSERT_EQ(0, mirror_peer_remove(&ioctx
, "DNE"));
1721 ASSERT_EQ(0, mirror_peer_list(&ioctx
, &peers
));
1722 expected_peers
= {};
1723 ASSERT_EQ(expected_peers
, peers
);
1725 ASSERT_EQ(0, mirror_mode_set(&ioctx
, cls::rbd::MIRROR_MODE_DISABLED
));
1726 ASSERT_EQ(0, mirror_mode_get(&ioctx
, &mirror_mode
));
1727 ASSERT_EQ(cls::rbd::MIRROR_MODE_DISABLED
, mirror_mode
);
1728 ASSERT_EQ(-ENOENT
, mirror_uuid_get(&ioctx
, &uuid
));
1731 TEST_F(TestClsRbd
, mirror_image
) {
1732 librados::IoCtx ioctx
;
1733 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1734 ioctx
.remove(RBD_MIRRORING
);
1736 std::map
<std::string
, std::string
> mirror_image_ids
;
1737 ASSERT_EQ(-ENOENT
, mirror_image_list(&ioctx
, "", 0, &mirror_image_ids
));
1739 cls::rbd::MirrorImage
image1(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
, "uuid1",
1740 cls::rbd::MIRROR_IMAGE_STATE_ENABLED
);
1741 cls::rbd::MirrorImage
image2(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
, "uuid2",
1742 cls::rbd::MIRROR_IMAGE_STATE_DISABLING
);
1743 cls::rbd::MirrorImage
image3(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
, "uuid3",
1744 cls::rbd::MIRROR_IMAGE_STATE_ENABLED
);
1746 ASSERT_EQ(0, mirror_image_set(&ioctx
, "image_id1", image1
));
1747 ASSERT_EQ(-ENOENT
, mirror_image_set(&ioctx
, "image_id2", image2
));
1748 image2
.state
= cls::rbd::MIRROR_IMAGE_STATE_ENABLED
;
1749 ASSERT_EQ(0, mirror_image_set(&ioctx
, "image_id2", image2
));
1750 image2
.state
= cls::rbd::MIRROR_IMAGE_STATE_DISABLING
;
1751 ASSERT_EQ(0, mirror_image_set(&ioctx
, "image_id2", image2
));
1752 ASSERT_EQ(-EINVAL
, mirror_image_set(&ioctx
, "image_id1", image2
));
1753 ASSERT_EQ(-EEXIST
, mirror_image_set(&ioctx
, "image_id3", image2
));
1754 ASSERT_EQ(0, mirror_image_set(&ioctx
, "image_id3", image3
));
1756 std::string image_id
;
1757 ASSERT_EQ(0, mirror_image_get_image_id(&ioctx
, "uuid2", &image_id
));
1758 ASSERT_EQ("image_id2", image_id
);
1760 cls::rbd::MirrorImage read_image
;
1761 ASSERT_EQ(0, mirror_image_get(&ioctx
, "image_id1", &read_image
));
1762 ASSERT_EQ(read_image
, image1
);
1763 ASSERT_EQ(0, mirror_image_get(&ioctx
, "image_id2", &read_image
));
1764 ASSERT_EQ(read_image
, image2
);
1765 ASSERT_EQ(0, mirror_image_get(&ioctx
, "image_id3", &read_image
));
1766 ASSERT_EQ(read_image
, image3
);
1768 ASSERT_EQ(0, mirror_image_list(&ioctx
, "", 1, &mirror_image_ids
));
1769 std::map
<std::string
, std::string
> expected_mirror_image_ids
= {
1770 {"image_id1", "uuid1"}};
1771 ASSERT_EQ(expected_mirror_image_ids
, mirror_image_ids
);
1773 ASSERT_EQ(0, mirror_image_list(&ioctx
, "image_id1", 2, &mirror_image_ids
));
1774 expected_mirror_image_ids
= {{"image_id2", "uuid2"}, {"image_id3", "uuid3"}};
1775 ASSERT_EQ(expected_mirror_image_ids
, mirror_image_ids
);
1777 ASSERT_EQ(0, mirror_image_remove(&ioctx
, "image_id2"));
1778 ASSERT_EQ(-ENOENT
, mirror_image_get_image_id(&ioctx
, "uuid2", &image_id
));
1779 ASSERT_EQ(-EBUSY
, mirror_image_remove(&ioctx
, "image_id1"));
1781 ASSERT_EQ(0, mirror_image_list(&ioctx
, "", 3, &mirror_image_ids
));
1782 expected_mirror_image_ids
= {{"image_id1", "uuid1"}, {"image_id3", "uuid3"}};
1783 ASSERT_EQ(expected_mirror_image_ids
, mirror_image_ids
);
1785 image1
.state
= cls::rbd::MIRROR_IMAGE_STATE_DISABLING
;
1786 image3
.state
= cls::rbd::MIRROR_IMAGE_STATE_DISABLING
;
1787 ASSERT_EQ(0, mirror_image_set(&ioctx
, "image_id1", image1
));
1788 ASSERT_EQ(0, mirror_image_get(&ioctx
, "image_id1", &read_image
));
1789 ASSERT_EQ(read_image
, image1
);
1790 ASSERT_EQ(0, mirror_image_set(&ioctx
, "image_id3", image3
));
1791 ASSERT_EQ(0, mirror_image_remove(&ioctx
, "image_id1"));
1792 ASSERT_EQ(0, mirror_image_remove(&ioctx
, "image_id3"));
1794 ASSERT_EQ(0, mirror_image_list(&ioctx
, "", 3, &mirror_image_ids
));
1795 expected_mirror_image_ids
= {};
1796 ASSERT_EQ(expected_mirror_image_ids
, mirror_image_ids
);
1799 TEST_F(TestClsRbd
, mirror_image_status
) {
1800 struct WatchCtx
: public librados::WatchCtx2
{
1801 librados::IoCtx
*m_ioctx
;
1803 explicit WatchCtx(librados::IoCtx
*ioctx
) : m_ioctx(ioctx
) {}
1804 void handle_notify(uint64_t notify_id
, uint64_t cookie
,
1805 uint64_t notifier_id
, bufferlist
& bl_
) override
{
1807 m_ioctx
->notify_ack(RBD_MIRRORING
, notify_id
, cookie
, bl
);
1809 void handle_error(uint64_t cookie
, int err
) override
{}
1812 map
<std::string
, cls::rbd::MirrorImage
> images
;
1813 map
<std::string
, cls::rbd::MirrorImageStatus
> statuses
;
1814 std::map
<cls::rbd::MirrorImageStatusState
, int32_t> states
;
1815 std::map
<std::string
, entity_inst_t
> instances
;
1816 cls::rbd::MirrorImageStatus read_status
;
1817 entity_inst_t read_instance
;
1818 uint64_t watch_handle
;
1819 librados::IoCtx ioctx
;
1821 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
1822 ioctx
.remove(RBD_MIRRORING
);
1824 int64_t instance_id
= librados::Rados(ioctx
).get_instance_id();
1826 // Test list fails on nonexistent RBD_MIRRORING object
1828 ASSERT_EQ(-ENOENT
, mirror_image_status_list(&ioctx
, "", 1024, &images
,
1833 cls::rbd::MirrorImage
image1(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
, "uuid1",
1834 cls::rbd::MIRROR_IMAGE_STATE_ENABLED
);
1835 cls::rbd::MirrorImage
image2(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
, "uuid2",
1836 cls::rbd::MIRROR_IMAGE_STATE_ENABLED
);
1837 cls::rbd::MirrorImage
image3(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
, "uuid3",
1838 cls::rbd::MIRROR_IMAGE_STATE_ENABLED
);
1840 ASSERT_EQ(0, mirror_image_set(&ioctx
, "image_id1", image1
));
1841 ASSERT_EQ(0, mirror_image_set(&ioctx
, "image_id2", image2
));
1842 ASSERT_EQ(0, mirror_image_set(&ioctx
, "image_id3", image3
));
1844 cls::rbd::MirrorImageSiteStatus
status1(
1845 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
, "");
1846 cls::rbd::MirrorImageSiteStatus
status2(
1847 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
, "");
1848 cls::rbd::MirrorImageSiteStatus
status3(
1849 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR
, "");
1851 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid1", status1
));
1854 ASSERT_EQ(0, mirror_image_status_list(&ioctx
, "", 1024, &images
, &statuses
));
1855 ASSERT_EQ(3U, images
.size());
1856 ASSERT_EQ(1U, statuses
.size());
1858 // Test status is down due to RBD_MIRRORING is not watched
1861 ASSERT_EQ(statuses
["image_id1"], cls::rbd::MirrorImageStatus
{{status1
}});
1862 ASSERT_EQ(0, mirror_image_status_get(&ioctx
, "uuid1", &read_status
));
1863 ASSERT_EQ(read_status
, cls::rbd::MirrorImageStatus
{{status1
}});
1865 // Test status summary. All statuses are unknown due to down.
1867 cls::rbd::MirrorPeer mirror_peer
{
1868 "uuid", cls::rbd::MIRROR_PEER_DIRECTION_RX
, "siteA", "client", "fsidA"};
1869 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx
, {mirror_peer
}, &states
));
1870 ASSERT_EQ(1U, states
.size());
1871 ASSERT_EQ(3, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
]);
1873 // Test get instance return -ESTALE due to down.
1875 ASSERT_EQ(-ESTALE
, mirror_image_instance_get(&ioctx
, "uuid1", &read_instance
));
1877 ASSERT_EQ(0, mirror_image_instance_list(&ioctx
, "", 1024, &instances
));
1878 ASSERT_TRUE(instances
.empty());
1880 // Test remove_down removes stale statuses
1882 ASSERT_EQ(0, mirror_image_status_remove_down(&ioctx
));
1883 ASSERT_EQ(-ENOENT
, mirror_image_status_get(&ioctx
, "uuid1", &read_status
));
1884 ASSERT_EQ(-ENOENT
, mirror_image_instance_get(&ioctx
, "uuid1", &read_instance
));
1885 ASSERT_EQ(0, mirror_image_status_list(&ioctx
, "", 1024, &images
, &statuses
));
1886 ASSERT_EQ(3U, images
.size());
1887 ASSERT_TRUE(statuses
.empty());
1888 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx
, {mirror_peer
}, &states
));
1889 ASSERT_EQ(1U, states
.size());
1890 ASSERT_EQ(3, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
]);
1892 // Test remove of status
1893 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid1", status1
));
1894 ASSERT_EQ(0, mirror_image_status_remove(&ioctx
, "uuid1"));
1895 ASSERT_EQ(-ENOENT
, mirror_image_instance_get(&ioctx
, "uuid1", &read_instance
));
1897 // Test statuses are not down after watcher is started
1899 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid1", status1
));
1901 WatchCtx
watch_ctx(&ioctx
);
1902 ASSERT_EQ(0, ioctx
.watch2(RBD_MIRRORING
, &watch_handle
, &watch_ctx
));
1904 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid2", status2
));
1905 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid3", status3
));
1907 ASSERT_EQ(0, mirror_image_status_get(&ioctx
, "uuid1", &read_status
));
1909 ASSERT_EQ(read_status
, cls::rbd::MirrorImageStatus
{{status1
}});
1910 ASSERT_EQ(0, mirror_image_status_get(&ioctx
, "uuid2", &read_status
));
1912 ASSERT_EQ(read_status
, cls::rbd::MirrorImageStatus
{{status2
}});
1913 ASSERT_EQ(0, mirror_image_status_get(&ioctx
, "uuid3", &read_status
));
1915 ASSERT_EQ(read_status
, cls::rbd::MirrorImageStatus
{{status3
}});
1919 ASSERT_EQ(0, mirror_image_status_list(&ioctx
, "", 1024, &images
, &statuses
));
1920 ASSERT_EQ(3U, images
.size());
1921 ASSERT_EQ(3U, statuses
.size());
1922 ASSERT_EQ(statuses
["image_id1"], cls::rbd::MirrorImageStatus
{{status1
}});
1923 ASSERT_EQ(statuses
["image_id2"], cls::rbd::MirrorImageStatus
{{status2
}});
1924 ASSERT_EQ(statuses
["image_id3"], cls::rbd::MirrorImageStatus
{{status3
}});
1927 ASSERT_EQ(0, mirror_image_instance_get(&ioctx
, "uuid1", &read_instance
));
1928 ASSERT_EQ(read_instance
.name
.num(), instance_id
);
1930 ASSERT_EQ(0, mirror_image_instance_list(&ioctx
, "", 1024, &instances
));
1931 ASSERT_EQ(3U, instances
.size());
1932 ASSERT_EQ(instances
["image_id1"].name
.num(), instance_id
);
1933 ASSERT_EQ(instances
["image_id2"].name
.num(), instance_id
);
1934 ASSERT_EQ(instances
["image_id3"].name
.num(), instance_id
);
1936 ASSERT_EQ(0, mirror_image_status_remove_down(&ioctx
));
1937 ASSERT_EQ(0, mirror_image_status_get(&ioctx
, "uuid1", &read_status
));
1938 ASSERT_EQ(read_status
, cls::rbd::MirrorImageStatus
{{status1
}});
1941 ASSERT_EQ(0, mirror_image_status_list(&ioctx
, "", 1024, &images
, &statuses
));
1942 ASSERT_EQ(3U, images
.size());
1943 ASSERT_EQ(3U, statuses
.size());
1944 ASSERT_EQ(statuses
["image_id1"], cls::rbd::MirrorImageStatus
{{status1
}});
1945 ASSERT_EQ(statuses
["image_id2"], cls::rbd::MirrorImageStatus
{{status2
}});
1946 ASSERT_EQ(statuses
["image_id3"], cls::rbd::MirrorImageStatus
{{status3
}});
1949 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx
, {mirror_peer
}, &states
));
1950 ASSERT_EQ(3U, states
.size());
1951 ASSERT_EQ(1, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
]);
1952 ASSERT_EQ(1, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
]);
1953 ASSERT_EQ(1, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR
]);
1957 status1
.state
= status3
.state
= cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
;
1958 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid1", status1
));
1959 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid3", status3
));
1960 ASSERT_EQ(0, mirror_image_status_get(&ioctx
, "uuid3", &read_status
));
1961 ASSERT_EQ(read_status
, cls::rbd::MirrorImageStatus
{{status3
}});
1964 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx
, {mirror_peer
}, &states
));
1965 ASSERT_EQ(1U, states
.size());
1966 ASSERT_EQ(3, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
]);
1970 ASSERT_EQ(0, mirror_uuid_set(&ioctx
, "mirror-uuid"));
1971 ASSERT_EQ(0, mirror_mode_set(&ioctx
, cls::rbd::MIRROR_MODE_POOL
));
1973 ASSERT_EQ(0, mirror_image_status_get(&ioctx
, "uuid1", &read_status
));
1974 cls::rbd::MirrorImageStatus
expected_status1({status1
});
1975 ASSERT_EQ(expected_status1
, read_status
);
1977 cls::rbd::MirrorImageSiteStatus
remote_status1(
1978 "fsidA", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
, "");
1979 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid1", remote_status1
));
1980 ASSERT_EQ(0, mirror_image_status_get(&ioctx
, "uuid1", &read_status
));
1981 remote_status1
.up
= true;
1982 expected_status1
= {{status1
, remote_status1
}};
1983 ASSERT_EQ(expected_status1
, read_status
);
1985 // summary under different modes
1986 cls::rbd::MirrorImageSiteStatus
remote_status2(
1987 "fsidA", cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
, "");
1988 remote_status2
.up
= true;
1989 cls::rbd::MirrorImageSiteStatus
remote_status3(
1990 "fsidA", cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
, "");
1991 remote_status3
.up
= true;
1993 status1
.state
= cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR
;
1994 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid1", status1
));
1995 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid2", status2
));
1996 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid3", status3
));
1997 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid2", remote_status2
));
1998 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, "uuid3", remote_status3
));
2000 expected_status1
= {{status1
, remote_status1
}};
2001 cls::rbd::MirrorImageStatus
expected_status2({status2
, remote_status2
});
2002 cls::rbd::MirrorImageStatus
expected_status3({status3
, remote_status3
});
2006 ASSERT_EQ(0, mirror_image_status_list(&ioctx
, "", 1024, &images
, &statuses
));
2007 ASSERT_EQ(3U, images
.size());
2008 ASSERT_EQ(3U, statuses
.size());
2009 ASSERT_EQ(statuses
["image_id1"], expected_status1
);
2010 ASSERT_EQ(statuses
["image_id2"], expected_status2
);
2011 ASSERT_EQ(statuses
["image_id3"], expected_status3
);
2014 mirror_peer
.mirror_peer_direction
= cls::rbd::MIRROR_PEER_DIRECTION_RX
;
2015 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx
, {mirror_peer
}, &states
));
2016 ASSERT_EQ(2U, states
.size());
2017 ASSERT_EQ(2, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
]);
2018 ASSERT_EQ(1, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR
]);
2021 mirror_peer
.mirror_peer_direction
= cls::rbd::MIRROR_PEER_DIRECTION_TX
;
2022 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx
, {mirror_peer
}, &states
));
2023 ASSERT_EQ(2U, states
.size());
2024 ASSERT_EQ(2, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
]);
2025 ASSERT_EQ(1, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
]);
2028 mirror_peer
.mirror_peer_direction
= cls::rbd::MIRROR_PEER_DIRECTION_RX_TX
;
2029 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx
, {mirror_peer
}, &states
));
2030 ASSERT_EQ(3U, states
.size());
2031 ASSERT_EQ(1, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_REPLAYING
]);
2032 ASSERT_EQ(1, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
]);
2033 ASSERT_EQ(1, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_ERROR
]);
2035 // Test statuses are down after removing watcher
2036 ioctx
.unwatch2(watch_handle
);
2038 ASSERT_EQ(0, mirror_image_status_list(&ioctx
, "", 1024, &images
, &statuses
));
2039 ASSERT_EQ(3U, images
.size());
2040 ASSERT_EQ(3U, statuses
.size());
2042 remote_status1
.up
= false;
2043 expected_status1
= {{status1
, remote_status1
}};
2044 ASSERT_EQ(statuses
["image_id1"], expected_status1
);
2046 remote_status2
.up
= false;
2047 expected_status2
= {{status2
, remote_status2
}};
2048 ASSERT_EQ(statuses
["image_id2"], expected_status2
);
2050 remote_status3
.up
= false;
2051 expected_status3
= {{status3
, remote_status3
}};
2052 ASSERT_EQ(statuses
["image_id3"], expected_status3
);
2054 ASSERT_EQ(0, mirror_image_status_get(&ioctx
, "uuid1", &read_status
));
2055 ASSERT_EQ(read_status
, expected_status1
);
2058 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx
, {mirror_peer
}, &states
));
2059 ASSERT_EQ(1U, states
.size());
2060 ASSERT_EQ(3, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
]);
2062 ASSERT_EQ(-ESTALE
, mirror_image_instance_get(&ioctx
, "uuid1", &read_instance
));
2064 ASSERT_EQ(0, mirror_image_instance_list(&ioctx
, "", 1024, &instances
));
2065 ASSERT_TRUE(instances
.empty());
2067 ASSERT_EQ(0, mirror_image_status_remove_down(&ioctx
));
2068 ASSERT_EQ(-ENOENT
, mirror_image_status_get(&ioctx
, "uuid1", &read_status
));
2072 ASSERT_EQ(0, mirror_image_status_list(&ioctx
, "", 1024, &images
, &statuses
));
2073 ASSERT_EQ(3U, images
.size());
2074 ASSERT_TRUE(statuses
.empty());
2077 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx
, {mirror_peer
}, &states
));
2078 ASSERT_EQ(1U, states
.size());
2079 ASSERT_EQ(3, states
[cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
]);
2083 image1
.state
= cls::rbd::MIRROR_IMAGE_STATE_DISABLING
;
2084 image2
.state
= cls::rbd::MIRROR_IMAGE_STATE_DISABLING
;
2085 image3
.state
= cls::rbd::MIRROR_IMAGE_STATE_DISABLING
;
2087 ASSERT_EQ(0, mirror_image_set(&ioctx
, "image_id1", image1
));
2088 ASSERT_EQ(0, mirror_image_set(&ioctx
, "image_id2", image2
));
2089 ASSERT_EQ(0, mirror_image_set(&ioctx
, "image_id3", image3
));
2091 ASSERT_EQ(0, mirror_image_remove(&ioctx
, "image_id1"));
2092 ASSERT_EQ(0, mirror_image_remove(&ioctx
, "image_id2"));
2093 ASSERT_EQ(0, mirror_image_remove(&ioctx
, "image_id3"));
2096 ASSERT_EQ(0, mirror_image_status_get_summary(&ioctx
, {}, &states
));
2097 ASSERT_EQ(0U, states
.size());
2099 // Test status list with large number of images
2102 ASSERT_EQ(0U, N
% 2);
2104 for (size_t i
= 0; i
< N
; i
++) {
2105 std::string id
= "id" + stringify(i
);
2106 std::string uuid
= "uuid" + stringify(i
);
2107 cls::rbd::MirrorImage
image(cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
, uuid
,
2108 cls::rbd::MIRROR_IMAGE_STATE_ENABLED
);
2109 cls::rbd::MirrorImageSiteStatus
status(
2110 "", cls::rbd::MIRROR_IMAGE_STATUS_STATE_UNKNOWN
, "");
2111 ASSERT_EQ(0, mirror_image_set(&ioctx
, id
, image
));
2112 ASSERT_EQ(0, mirror_image_status_set(&ioctx
, uuid
, status
));
2115 std::string last_read
= "";
2118 ASSERT_EQ(0, mirror_image_status_list(&ioctx
, last_read
, N
* 2, &images
,
2120 ASSERT_EQ(N
, images
.size());
2121 ASSERT_EQ(N
, statuses
.size());
2125 ASSERT_EQ(0, mirror_image_status_list(&ioctx
, last_read
, N
/ 2, &images
,
2127 ASSERT_EQ(N
/ 2, images
.size());
2128 ASSERT_EQ(N
/ 2, statuses
.size());
2130 last_read
= images
.rbegin()->first
;
2133 ASSERT_EQ(0, mirror_image_status_list(&ioctx
, last_read
, N
/ 2, &images
,
2135 ASSERT_EQ(N
/ 2, images
.size());
2136 ASSERT_EQ(N
/ 2, statuses
.size());
2138 last_read
= images
.rbegin()->first
;
2141 ASSERT_EQ(0, mirror_image_status_list(&ioctx
, last_read
, N
/ 2, &images
,
2143 ASSERT_EQ(0U, images
.size());
2144 ASSERT_EQ(0U, statuses
.size());
2147 TEST_F(TestClsRbd
, mirror_image_map
)
2149 librados::IoCtx ioctx
;
2150 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2151 ioctx
.remove(RBD_MIRRORING
);
2153 std::map
<std::string
, cls::rbd::MirrorImageMap
> image_mapping
;
2154 ASSERT_EQ(-ENOENT
, mirror_image_map_list(&ioctx
, "", 0, &image_mapping
));
2156 utime_t expected_time
= ceph_clock_now();
2158 bufferlist expected_data
;
2159 expected_data
.append("test");
2161 std::map
<std::string
, cls::rbd::MirrorImageMap
> expected_image_mapping
;
2162 while (expected_image_mapping
.size() < 1024) {
2163 librados::ObjectWriteOperation op
;
2164 for (uint32_t i
= 0; i
< 32; ++i
) {
2165 std::string global_image_id
{stringify(expected_image_mapping
.size())};
2166 cls::rbd::MirrorImageMap mirror_image_map
{
2167 stringify(i
), expected_time
, expected_data
};
2168 expected_image_mapping
.emplace(global_image_id
, mirror_image_map
);
2170 mirror_image_map_update(&op
, global_image_id
, mirror_image_map
);
2172 ASSERT_EQ(0, ioctx
.operate(RBD_MIRRORING
, &op
));
2175 ASSERT_EQ(0, mirror_image_map_list(&ioctx
, "", 1000, &image_mapping
));
2176 ASSERT_EQ(1000U, image_mapping
.size());
2178 ASSERT_EQ(0, mirror_image_map_list(&ioctx
, image_mapping
.rbegin()->first
,
2179 1000, &image_mapping
));
2180 ASSERT_EQ(24U, image_mapping
.size());
2182 const auto& image_map
= *image_mapping
.begin();
2183 ASSERT_EQ("978", image_map
.first
);
2185 cls::rbd::MirrorImageMap expected_mirror_image_map
{
2186 stringify(18), expected_time
, expected_data
};
2187 ASSERT_EQ(expected_mirror_image_map
, image_map
.second
);
2189 expected_time
= ceph_clock_now();
2190 expected_mirror_image_map
.mapped_time
= expected_time
;
2192 expected_data
.append("update");
2193 expected_mirror_image_map
.data
= expected_data
;
2195 librados::ObjectWriteOperation op
;
2196 mirror_image_map_remove(&op
, "1");
2197 mirror_image_map_update(&op
, "10", expected_mirror_image_map
);
2198 ASSERT_EQ(0, ioctx
.operate(RBD_MIRRORING
, &op
));
2200 ASSERT_EQ(0, mirror_image_map_list(&ioctx
, "0", 1, &image_mapping
));
2201 ASSERT_EQ(1U, image_mapping
.size());
2203 const auto& updated_image_map
= *image_mapping
.begin();
2204 ASSERT_EQ("10", updated_image_map
.first
);
2205 ASSERT_EQ(expected_mirror_image_map
, updated_image_map
.second
);
2208 TEST_F(TestClsRbd
, mirror_instances
) {
2209 librados::IoCtx ioctx
;
2210 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2211 ioctx
.remove(RBD_MIRROR_LEADER
);
2213 std::vector
<std::string
> instance_ids
;
2214 ASSERT_EQ(-ENOENT
, mirror_instances_list(&ioctx
, &instance_ids
));
2216 ASSERT_EQ(0, ioctx
.create(RBD_MIRROR_LEADER
, true));
2217 ASSERT_EQ(0, mirror_instances_list(&ioctx
, &instance_ids
));
2218 ASSERT_EQ(0U, instance_ids
.size());
2220 ASSERT_EQ(0, mirror_instances_add(&ioctx
, "instance_id1"));
2221 ASSERT_EQ(0, mirror_instances_list(&ioctx
, &instance_ids
));
2222 ASSERT_EQ(1U, instance_ids
.size());
2223 ASSERT_EQ(instance_ids
[0], "instance_id1");
2225 ASSERT_EQ(0, mirror_instances_add(&ioctx
, "instance_id1"));
2226 ASSERT_EQ(0, mirror_instances_add(&ioctx
, "instance_id2"));
2227 ASSERT_EQ(0, mirror_instances_list(&ioctx
, &instance_ids
));
2228 ASSERT_EQ(2U, instance_ids
.size());
2230 ASSERT_EQ(0, mirror_instances_remove(&ioctx
, "instance_id1"));
2231 ASSERT_EQ(0, mirror_instances_list(&ioctx
, &instance_ids
));
2232 ASSERT_EQ(1U, instance_ids
.size());
2233 ASSERT_EQ(instance_ids
[0], "instance_id2");
2235 ASSERT_EQ(0, mirror_instances_remove(&ioctx
, "instance_id2"));
2236 ASSERT_EQ(0, mirror_instances_list(&ioctx
, &instance_ids
));
2237 ASSERT_EQ(0U, instance_ids
.size());
2240 TEST_F(TestClsRbd
, mirror_snapshot
) {
2241 librados::IoCtx ioctx
;
2242 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2244 string oid
= get_temp_image_name();
2245 ASSERT_EQ(0, create_image(&ioctx
, oid
, 10, 22, 0, oid
, -1));
2247 cls::rbd::MirrorSnapshotNamespace primary
= {
2248 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY
, {"peer1", "peer2"}, "",
2250 cls::rbd::MirrorSnapshotNamespace non_primary
= {
2251 cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY
, {"peer1"}, "uuid", 123};
2252 librados::ObjectWriteOperation op
;
2253 ::librbd::cls_client::snapshot_add(&op
, 1, "primary", primary
);
2254 ::librbd::cls_client::snapshot_add(&op
, 2, "non_primary", non_primary
);
2255 ASSERT_EQ(0, ioctx
.operate(oid
, &op
));
2257 cls::rbd::SnapshotInfo snap
;
2258 ASSERT_EQ(0, snapshot_get(&ioctx
, oid
, 1, &snap
));
2259 auto sn
= boost::get
<cls::rbd::MirrorSnapshotNamespace
>(
2260 &snap
.snapshot_namespace
);
2261 ASSERT_NE(nullptr, sn
);
2262 ASSERT_EQ(primary
, *sn
);
2263 ASSERT_EQ(2U, sn
->mirror_peer_uuids
.size());
2264 ASSERT_EQ(1U, sn
->mirror_peer_uuids
.count("peer1"));
2265 ASSERT_EQ(1U, sn
->mirror_peer_uuids
.count("peer2"));
2267 ASSERT_EQ(-ENOENT
, mirror_image_snapshot_unlink_peer(&ioctx
, oid
, 1, "peer"));
2268 ASSERT_EQ(0, mirror_image_snapshot_unlink_peer(&ioctx
, oid
, 1, "peer1"));
2269 ASSERT_EQ(-ENOENT
, mirror_image_snapshot_unlink_peer(&ioctx
, oid
, 1,
2271 ASSERT_EQ(0, snapshot_get(&ioctx
, oid
, 1, &snap
));
2272 sn
= boost::get
<cls::rbd::MirrorSnapshotNamespace
>(
2273 &snap
.snapshot_namespace
);
2274 ASSERT_NE(nullptr, sn
);
2275 ASSERT_EQ(1U, sn
->mirror_peer_uuids
.size());
2276 ASSERT_EQ(1U, sn
->mirror_peer_uuids
.count("peer2"));
2278 ASSERT_EQ(-ERESTART
,
2279 mirror_image_snapshot_unlink_peer(&ioctx
, oid
, 1, "peer2"));
2280 ASSERT_EQ(0, snapshot_get(&ioctx
, oid
, 1, &snap
));
2281 sn
= boost::get
<cls::rbd::MirrorSnapshotNamespace
>(
2282 &snap
.snapshot_namespace
);
2283 ASSERT_NE(nullptr, sn
);
2284 ASSERT_EQ(1U, sn
->mirror_peer_uuids
.size());
2285 ASSERT_EQ(1U, sn
->mirror_peer_uuids
.count("peer2"));
2287 ASSERT_EQ(0, snapshot_get(&ioctx
, oid
, 2, &snap
));
2288 auto nsn
= boost::get
<cls::rbd::MirrorSnapshotNamespace
>(
2289 &snap
.snapshot_namespace
);
2290 ASSERT_NE(nullptr, nsn
);
2291 ASSERT_EQ(non_primary
, *nsn
);
2292 ASSERT_EQ(1U, nsn
->mirror_peer_uuids
.size());
2293 ASSERT_EQ(1U, nsn
->mirror_peer_uuids
.count("peer1"));
2294 ASSERT_FALSE(nsn
->complete
);
2295 ASSERT_EQ(nsn
->last_copied_object_number
, 0);
2297 ASSERT_EQ(0, mirror_image_snapshot_set_copy_progress(&ioctx
, oid
, 2, true,
2299 ASSERT_EQ(0, snapshot_get(&ioctx
, oid
, 2, &snap
));
2300 nsn
= boost::get
<cls::rbd::MirrorSnapshotNamespace
>(
2301 &snap
.snapshot_namespace
);
2302 ASSERT_NE(nullptr, nsn
);
2303 ASSERT_TRUE(nsn
->complete
);
2304 ASSERT_EQ(nsn
->last_copied_object_number
, 10);
2306 ASSERT_EQ(0, mirror_image_snapshot_unlink_peer(&ioctx
, oid
, 2, "peer1"));
2308 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 1));
2309 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 2));
2312 TEST_F(TestClsRbd
, group_dir_list
) {
2313 librados::IoCtx ioctx
;
2314 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2316 string group_id1
= "cgid1";
2317 string group_name1
= "cgname1";
2318 string group_id2
= "cgid2";
2319 string group_name2
= "cgname2";
2320 ASSERT_EQ(0, group_dir_add(&ioctx
, RBD_GROUP_DIRECTORY
, group_name1
, group_id1
));
2321 ASSERT_EQ(0, group_dir_add(&ioctx
, RBD_GROUP_DIRECTORY
, group_name2
, group_id2
));
2323 map
<string
, string
> cgs
;
2324 ASSERT_EQ(0, group_dir_list(&ioctx
, RBD_GROUP_DIRECTORY
, "", 10, &cgs
));
2326 ASSERT_EQ(2U, cgs
.size());
2328 auto it
= cgs
.begin();
2329 ASSERT_EQ(group_id1
, it
->second
);
2330 ASSERT_EQ(group_name1
, it
->first
);
2333 ASSERT_EQ(group_id2
, it
->second
);
2334 ASSERT_EQ(group_name2
, it
->first
);
2337 void add_group_to_dir(librados::IoCtx ioctx
, string group_id
, string group_name
) {
2338 ASSERT_EQ(0, group_dir_add(&ioctx
, RBD_GROUP_DIRECTORY
, group_name
, group_id
));
2341 ASSERT_EQ(0, ioctx
.omap_get_keys(RBD_GROUP_DIRECTORY
, "", 10, &keys
));
2342 ASSERT_EQ(2U, keys
.size());
2343 ASSERT_EQ("id_" + group_id
, *keys
.begin());
2344 ASSERT_EQ("name_" + group_name
, *keys
.rbegin());
2347 TEST_F(TestClsRbd
, group_dir_add
) {
2348 librados::IoCtx ioctx
;
2349 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2350 ioctx
.remove(RBD_GROUP_DIRECTORY
);
2352 string group_id
= "cgid";
2353 string group_name
= "cgname";
2354 add_group_to_dir(ioctx
, group_id
, group_name
);
2357 TEST_F(TestClsRbd
, dir_add_already_existing
) {
2358 librados::IoCtx ioctx
;
2359 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2360 ioctx
.remove(RBD_GROUP_DIRECTORY
);
2362 string group_id
= "cgidexisting";
2363 string group_name
= "cgnameexisting";
2364 add_group_to_dir(ioctx
, group_id
, group_name
);
2366 ASSERT_EQ(-EEXIST
, group_dir_add(&ioctx
, RBD_GROUP_DIRECTORY
, group_name
, group_id
));
2369 TEST_F(TestClsRbd
, group_dir_rename
) {
2370 librados::IoCtx ioctx
;
2371 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2372 ioctx
.remove(RBD_GROUP_DIRECTORY
);
2374 string group_id
= "cgid";
2375 string src_name
= "cgnamesrc";
2376 string dest_name
= "cgnamedest";
2377 add_group_to_dir(ioctx
, group_id
, src_name
);
2379 ASSERT_EQ(0, group_dir_rename(&ioctx
, RBD_GROUP_DIRECTORY
,
2380 src_name
, dest_name
, group_id
));
2381 map
<string
, string
> cgs
;
2382 ASSERT_EQ(0, group_dir_list(&ioctx
, RBD_GROUP_DIRECTORY
, "", 10, &cgs
));
2383 ASSERT_EQ(1U, cgs
.size());
2384 auto it
= cgs
.begin();
2385 ASSERT_EQ(group_id
, it
->second
);
2386 ASSERT_EQ(dest_name
, it
->first
);
2388 // destination group name existing
2389 ASSERT_EQ(-EEXIST
, group_dir_rename(&ioctx
, RBD_GROUP_DIRECTORY
,
2390 dest_name
, dest_name
, group_id
));
2391 ASSERT_EQ(0, group_dir_remove(&ioctx
, RBD_GROUP_DIRECTORY
, dest_name
, group_id
));
2392 // source group name missing
2393 ASSERT_EQ(-ENOENT
, group_dir_rename(&ioctx
, RBD_GROUP_DIRECTORY
,
2394 dest_name
, src_name
, group_id
));
2397 TEST_F(TestClsRbd
, group_dir_remove
) {
2398 librados::IoCtx ioctx
;
2399 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2400 ioctx
.remove(RBD_GROUP_DIRECTORY
);
2402 string group_id
= "cgidtodel";
2403 string group_name
= "cgnametodel";
2404 add_group_to_dir(ioctx
, group_id
, group_name
);
2406 ASSERT_EQ(0, group_dir_remove(&ioctx
, RBD_GROUP_DIRECTORY
, group_name
, group_id
));
2409 ASSERT_EQ(0, ioctx
.omap_get_keys(RBD_GROUP_DIRECTORY
, "", 10, &keys
));
2410 ASSERT_EQ(0U, keys
.size());
2413 TEST_F(TestClsRbd
, group_dir_remove_missing
) {
2414 librados::IoCtx ioctx
;
2415 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2416 ioctx
.remove(RBD_GROUP_DIRECTORY
);
2418 string group_id
= "cgidtodelmissing";
2419 string group_name
= "cgnametodelmissing";
2420 // These two lines ensure that RBD_GROUP_DIRECTORY exists. It's important for the
2422 add_group_to_dir(ioctx
, group_id
, group_name
);
2424 ASSERT_EQ(0, group_dir_remove(&ioctx
, RBD_GROUP_DIRECTORY
, group_name
, group_id
));
2427 ASSERT_EQ(-ENOENT
, group_dir_remove(&ioctx
, RBD_GROUP_DIRECTORY
, group_name
, group_id
));
2430 ASSERT_EQ(0, ioctx
.omap_get_keys(RBD_GROUP_DIRECTORY
, "", 10, &keys
));
2431 ASSERT_EQ(0U, keys
.size());
2434 void test_image_add(librados::IoCtx
&ioctx
, const string
& group_id
,
2435 const string
& image_id
, int64_t pool_id
) {
2437 cls::rbd::GroupImageStatus
st(image_id
, pool_id
,
2438 cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE
);
2439 ASSERT_EQ(0, group_image_set(&ioctx
, group_id
, st
));
2442 ASSERT_EQ(0, ioctx
.omap_get_keys(group_id
, "", 10, &keys
));
2444 auto it
= keys
.begin();
2445 ASSERT_EQ(1U, keys
.size());
2447 string image_key
= cls::rbd::GroupImageSpec(image_id
, pool_id
).image_key();
2448 ASSERT_EQ(image_key
, *it
);
2451 TEST_F(TestClsRbd
, group_image_add
) {
2452 librados::IoCtx ioctx
;
2453 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2455 string group_id
= "group_id";
2456 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2458 int64_t pool_id
= ioctx
.get_id();
2459 string image_id
= "image_id";
2460 test_image_add(ioctx
, group_id
, image_id
, pool_id
);
2463 TEST_F(TestClsRbd
, group_image_remove
) {
2464 librados::IoCtx ioctx
;
2465 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2467 string group_id
= "group_id1";
2468 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2470 int64_t pool_id
= ioctx
.get_id();
2471 string image_id
= "image_id";
2472 test_image_add(ioctx
, group_id
, image_id
, pool_id
);
2474 cls::rbd::GroupImageSpec
spec(image_id
, pool_id
);
2475 ASSERT_EQ(0, group_image_remove(&ioctx
, group_id
, spec
));
2477 ASSERT_EQ(0, ioctx
.omap_get_keys(group_id
, "", 10, &keys
));
2478 ASSERT_EQ(0U, keys
.size());
2481 TEST_F(TestClsRbd
, group_image_list
) {
2482 librados::IoCtx ioctx
;
2483 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2485 string group_id
= "group_id2";
2486 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2488 int64_t pool_id
= ioctx
.get_id();
2489 string image_id
= "imageid"; // Image id shouldn't contain underscores
2490 test_image_add(ioctx
, group_id
, image_id
, pool_id
);
2492 vector
<cls::rbd::GroupImageStatus
> images
;
2493 cls::rbd::GroupImageSpec empty_image_spec
= cls::rbd::GroupImageSpec();
2494 ASSERT_EQ(0, group_image_list(&ioctx
, group_id
, empty_image_spec
, 1024,
2496 ASSERT_EQ(1U, images
.size());
2497 ASSERT_EQ(image_id
, images
[0].spec
.image_id
);
2498 ASSERT_EQ(pool_id
, images
[0].spec
.pool_id
);
2499 ASSERT_EQ(cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE
, images
[0].state
);
2501 cls::rbd::GroupImageStatus last_image
= *images
.rbegin();
2502 ASSERT_EQ(0, group_image_list(&ioctx
, group_id
, last_image
.spec
, 1024,
2504 ASSERT_EQ(0U, images
.size());
2507 TEST_F(TestClsRbd
, group_image_clean
) {
2508 librados::IoCtx ioctx
;
2509 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2511 string group_id
= "group_id3";
2512 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2514 int64_t pool_id
= ioctx
.get_id();
2515 string image_id
= "image_id";
2516 test_image_add(ioctx
, group_id
, image_id
, pool_id
);
2518 cls::rbd::GroupImageStatus
incomplete_st(image_id
, pool_id
,
2519 cls::rbd::GROUP_IMAGE_LINK_STATE_INCOMPLETE
);
2521 ASSERT_EQ(0, group_image_set(&ioctx
, group_id
, incomplete_st
));
2522 // Set to dirty first in order to make sure that group_image_clean
2523 // actually does something.
2524 cls::rbd::GroupImageStatus
attached_st(image_id
, pool_id
,
2525 cls::rbd::GROUP_IMAGE_LINK_STATE_ATTACHED
);
2526 ASSERT_EQ(0, group_image_set(&ioctx
, group_id
, attached_st
));
2528 string image_key
= cls::rbd::GroupImageSpec(image_id
, pool_id
).image_key();
2530 map
<string
, bufferlist
> vals
;
2531 ASSERT_EQ(0, ioctx
.omap_get_vals(group_id
, "", 10, &vals
));
2533 cls::rbd::GroupImageLinkState ref_state
;
2534 auto it
= vals
[image_key
].cbegin();
2535 decode(ref_state
, it
);
2536 ASSERT_EQ(cls::rbd::GROUP_IMAGE_LINK_STATE_ATTACHED
, ref_state
);
2539 TEST_F(TestClsRbd
, image_group_add
) {
2540 librados::IoCtx ioctx
;
2541 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2543 int64_t pool_id
= ioctx
.get_id();
2544 string image_id
= "imageid";
2546 ASSERT_EQ(0, create_image(&ioctx
, image_id
, 2<<20, 0,
2547 RBD_FEATURE_LAYERING
, image_id
, -1));
2549 string group_id
= "group_id";
2551 cls::rbd::GroupSpec
spec(group_id
, pool_id
);
2552 ASSERT_EQ(0, image_group_add(&ioctx
, image_id
, spec
));
2554 map
<string
, bufferlist
> vals
;
2555 ASSERT_EQ(0, ioctx
.omap_get_vals(image_id
, "", RBD_GROUP_REF
, 10, &vals
));
2557 cls::rbd::GroupSpec val_spec
;
2558 auto it
= vals
[RBD_GROUP_REF
].cbegin();
2559 decode(val_spec
, it
);
2561 ASSERT_EQ(group_id
, val_spec
.group_id
);
2562 ASSERT_EQ(pool_id
, val_spec
.pool_id
);
2565 TEST_F(TestClsRbd
, image_group_remove
) {
2566 librados::IoCtx ioctx
;
2567 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2569 int64_t pool_id
= ioctx
.get_id();
2570 string image_id
= "image_id";
2572 ASSERT_EQ(0, create_image(&ioctx
, image_id
, 2<<20, 0,
2573 RBD_FEATURE_LAYERING
, image_id
, -1));
2575 string group_id
= "group_id";
2577 cls::rbd::GroupSpec
spec(group_id
, pool_id
);
2578 ASSERT_EQ(0, image_group_add(&ioctx
, image_id
, spec
));
2579 // Add reference in order to make sure that image_group_remove actually
2581 ASSERT_EQ(0, image_group_remove(&ioctx
, image_id
, spec
));
2583 map
<string
, bufferlist
> vals
;
2584 ASSERT_EQ(0, ioctx
.omap_get_vals(image_id
, "", RBD_GROUP_REF
, 10, &vals
));
2586 ASSERT_EQ(0U, vals
.size());
2589 TEST_F(TestClsRbd
, image_group_get
) {
2590 librados::IoCtx ioctx
;
2591 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2593 int64_t pool_id
= ioctx
.get_id();
2594 string image_id
= "imageidgroupspec";
2596 ASSERT_EQ(0, create_image(&ioctx
, image_id
, 2<<20, 0,
2597 RBD_FEATURE_LAYERING
, image_id
, -1));
2599 string group_id
= "group_id_get_group_spec";
2601 cls::rbd::GroupSpec
spec_add(group_id
, pool_id
);
2602 ASSERT_EQ(0, image_group_add(&ioctx
, image_id
, spec_add
));
2604 cls::rbd::GroupSpec spec
;
2605 ASSERT_EQ(0, image_group_get(&ioctx
, image_id
, &spec
));
2607 ASSERT_EQ(group_id
, spec
.group_id
);
2608 ASSERT_EQ(pool_id
, spec
.pool_id
);
2611 TEST_F(TestClsRbd
, group_snap_set_empty_name
) {
2612 librados::IoCtx ioctx
;
2613 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2615 string image_id
= "image_id_snap_add_emtpy_name";
2617 string group_id
= "group_id_snap_add_empty_name";
2618 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2620 string snap_id
= "snap_id";
2621 cls::rbd::GroupSnapshot snap
= {snap_id
, "", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
};
2622 ASSERT_EQ(-EINVAL
, group_snap_set(&ioctx
, group_id
, snap
));
2625 TEST_F(TestClsRbd
, group_snap_set_empty_id
) {
2626 librados::IoCtx ioctx
;
2627 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2629 string image_id
= "image_id_snap_add_empty_id";
2631 string group_id
= "group_id_snap_add_empty_id";
2632 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2634 string snap_id
= "snap_id";
2635 cls::rbd::GroupSnapshot snap
= {"", "snap_name", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
};
2636 ASSERT_EQ(-EINVAL
, group_snap_set(&ioctx
, group_id
, snap
));
2639 TEST_F(TestClsRbd
, group_snap_set_duplicate_id
) {
2640 librados::IoCtx ioctx
;
2641 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2643 string image_id
= "image_id_snap_add_duplicate_id";
2645 string group_id
= "group_id_snap_add_duplicate_id";
2646 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2648 string snap_id
= "snap_id";
2649 cls::rbd::GroupSnapshot snap
= {snap_id
, "snap_name", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
};
2650 ASSERT_EQ(0, group_snap_set(&ioctx
, group_id
, snap
));
2652 cls::rbd::GroupSnapshot snap1
= {snap_id
, "snap_name1", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
};
2653 ASSERT_EQ(-EEXIST
, group_snap_set(&ioctx
, group_id
, snap1
));
2656 TEST_F(TestClsRbd
, group_snap_set_duplicate_name
) {
2657 librados::IoCtx ioctx
;
2658 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2660 string image_id
= "image_id_snap_add_duplicate_name";
2662 string group_id
= "group_id_snap_add_duplicate_name";
2663 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2665 string snap_id1
= "snap_id1";
2666 cls::rbd::GroupSnapshot snap
= {snap_id1
, "snap_name", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
};
2667 ASSERT_EQ(0, group_snap_set(&ioctx
, group_id
, snap
));
2669 string snap_id2
= "snap_id2";
2670 cls::rbd::GroupSnapshot snap1
= {snap_id2
, "snap_name", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
};
2671 ASSERT_EQ(-EEXIST
, group_snap_set(&ioctx
, group_id
, snap1
));
2674 TEST_F(TestClsRbd
, group_snap_set
) {
2675 librados::IoCtx ioctx
;
2676 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2678 string image_id
= "image_id_snap_add";
2680 string group_id
= "group_id_snap_add";
2681 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2683 string snap_id
= "snap_id";
2684 cls::rbd::GroupSnapshot snap
= {snap_id
, "test_snapshot", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
};
2685 ASSERT_EQ(0, group_snap_set(&ioctx
, group_id
, snap
));
2688 ASSERT_EQ(0, ioctx
.omap_get_keys(group_id
, "", 10, &keys
));
2690 auto it
= keys
.begin();
2691 ASSERT_EQ(1U, keys
.size());
2693 string snap_key
= "snapshot_" + stringify(snap
.id
);
2694 ASSERT_EQ(snap_key
, *it
);
2697 TEST_F(TestClsRbd
, group_snap_list
) {
2698 librados::IoCtx ioctx
;
2699 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2701 string image_id
= "image_id_snap_list";
2703 string group_id
= "group_id_snap_list";
2704 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2706 string snap_id1
= "snap_id1";
2707 cls::rbd::GroupSnapshot snap1
= {snap_id1
, "test_snapshot1", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
};
2708 ASSERT_EQ(0, group_snap_set(&ioctx
, group_id
, snap1
));
2710 string snap_id2
= "snap_id2";
2711 cls::rbd::GroupSnapshot snap2
= {snap_id2
, "test_snapshot2", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
};
2712 ASSERT_EQ(0, group_snap_set(&ioctx
, group_id
, snap2
));
2714 std::vector
<cls::rbd::GroupSnapshot
> snapshots
;
2715 ASSERT_EQ(0, group_snap_list(&ioctx
, group_id
, cls::rbd::GroupSnapshot(), 10, &snapshots
));
2716 ASSERT_EQ(2U, snapshots
.size());
2717 ASSERT_EQ(snap_id1
, snapshots
[0].id
);
2718 ASSERT_EQ(snap_id2
, snapshots
[1].id
);
2721 static std::string
hexify(int v
) {
2723 oss
<< std::setw(8) << std::setfill('0') << std::hex
<< v
;
2728 TEST_F(TestClsRbd
, group_snap_list_max_return
) {
2729 librados::IoCtx ioctx
;
2730 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2732 string image_id
= "image_id_snap_list_max_return";
2734 string group_id
= "group_id_snap_list_max_return";
2735 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2737 for (int i
= 0; i
< 15; ++i
) {
2738 string snap_id
= "snap_id" + hexify(i
);
2739 cls::rbd::GroupSnapshot snap
= {snap_id
,
2740 "test_snapshot" + hexify(i
),
2741 cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
};
2742 ASSERT_EQ(0, group_snap_set(&ioctx
, group_id
, snap
));
2745 std::vector
<cls::rbd::GroupSnapshot
> snapshots
;
2746 ASSERT_EQ(0, group_snap_list(&ioctx
, group_id
, cls::rbd::GroupSnapshot(), 10, &snapshots
));
2747 ASSERT_EQ(10U, snapshots
.size());
2749 for (int i
= 0; i
< 10; ++i
) {
2750 string snap_id
= "snap_id" + hexify(i
);
2751 ASSERT_EQ(snap_id
, snapshots
[i
].id
);
2754 cls::rbd::GroupSnapshot last_snap
= *snapshots
.rbegin();
2756 ASSERT_EQ(0, group_snap_list(&ioctx
, group_id
, last_snap
, 10, &snapshots
));
2757 ASSERT_EQ(5U, snapshots
.size());
2758 for (int i
= 10; i
< 15; ++i
) {
2759 string snap_id
= "snap_id" + hexify(i
);
2760 ASSERT_EQ(snap_id
, snapshots
[i
- 10].id
);
2764 TEST_F(TestClsRbd
, group_snap_remove
) {
2765 librados::IoCtx ioctx
;
2767 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2769 string image_id
= "image_id_snap_remove";
2771 string group_id
= "group_id_snap_remove";
2772 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2774 string snap_id
= "snap_id";
2775 cls::rbd::GroupSnapshot snap
= {snap_id
, "test_snapshot", cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
};
2776 ASSERT_EQ(0, group_snap_set(&ioctx
, group_id
, snap
));
2779 ASSERT_EQ(0, ioctx
.omap_get_keys(group_id
, "", 10, &keys
));
2781 auto it
= keys
.begin();
2782 ASSERT_EQ(1U, keys
.size());
2784 string snap_key
= "snapshot_" + stringify(snap
.id
);
2785 ASSERT_EQ(snap_key
, *it
);
2787 // Remove the snapshot
2789 ASSERT_EQ(0, group_snap_remove(&ioctx
, group_id
, snap_id
));
2791 ASSERT_EQ(0, ioctx
.omap_get_keys(group_id
, "", 10, &keys
));
2793 ASSERT_EQ(0U, keys
.size());
2796 TEST_F(TestClsRbd
, group_snap_get_by_id
) {
2797 librados::IoCtx ioctx
;
2799 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2801 string image_id
= "image_id_snap_get_by_id";
2803 string group_id
= "group_id_snap_get_by_id";
2804 ASSERT_EQ(0, ioctx
.create(group_id
, true));
2806 string snap_id
= "snap_id";
2807 cls::rbd::GroupSnapshot snap
= {snap_id
,
2809 cls::rbd::GROUP_SNAPSHOT_STATE_INCOMPLETE
};
2810 ASSERT_EQ(0, group_snap_set(&ioctx
, group_id
, snap
));
2812 cls::rbd::GroupSnapshot received_snap
;
2813 ASSERT_EQ(0, group_snap_get_by_id(&ioctx
, group_id
, snap_id
, &received_snap
));
2815 ASSERT_EQ(snap
.id
, received_snap
.id
);
2816 ASSERT_EQ(snap
.name
, received_snap
.name
);
2817 ASSERT_EQ(snap
.state
, received_snap
.state
);
2820 TEST_F(TestClsRbd
, trash_methods
)
2822 librados::IoCtx ioctx
;
2823 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2825 string id
= "123456789";
2826 string id2
= "123456780";
2828 std::map
<string
, cls::rbd::TrashImageSpec
> entries
;
2829 ASSERT_EQ(-ENOENT
, trash_list(&ioctx
, "", 1024, &entries
));
2831 utime_t now1
= ceph_clock_now();
2832 utime_t now1_delay
= now1
;
2834 cls::rbd::TrashImageSpec
trash_spec(cls::rbd::TRASH_IMAGE_SOURCE_USER
, "name",
2836 ASSERT_EQ(0, trash_add(&ioctx
, id
, trash_spec
));
2838 utime_t now2
= ceph_clock_now();
2839 utime_t now2_delay
= now2
;
2841 cls::rbd::TrashImageSpec
trash_spec2(cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING
,
2842 "name2", now2
, now2_delay
);
2843 ASSERT_EQ(-EEXIST
, trash_add(&ioctx
, id
, trash_spec2
));
2845 ASSERT_EQ(0, trash_remove(&ioctx
, id
));
2846 ASSERT_EQ(-ENOENT
, trash_remove(&ioctx
, id
));
2848 ASSERT_EQ(0, trash_list(&ioctx
, "", 1024, &entries
));
2849 ASSERT_TRUE(entries
.empty());
2851 ASSERT_EQ(0, trash_add(&ioctx
, id
, trash_spec2
));
2852 ASSERT_EQ(0, trash_add(&ioctx
, id2
, trash_spec
));
2854 ASSERT_EQ(0, trash_list(&ioctx
, "", 1, &entries
));
2855 ASSERT_TRUE(entries
.find(id2
) != entries
.end());
2856 ASSERT_EQ(cls::rbd::TRASH_IMAGE_SOURCE_USER
, entries
[id2
].source
);
2857 ASSERT_EQ(std::string("name"), entries
[id2
].name
);
2858 ASSERT_EQ(now1
, entries
[id2
].deletion_time
);
2859 ASSERT_EQ(now1_delay
, entries
[id2
].deferment_end_time
);
2861 ASSERT_EQ(0, trash_list(&ioctx
, id2
, 1, &entries
));
2862 ASSERT_TRUE(entries
.find(id
) != entries
.end());
2863 ASSERT_EQ(cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING
, entries
[id
].source
);
2864 ASSERT_EQ(std::string("name2"), entries
[id
].name
);
2865 ASSERT_EQ(now2
, entries
[id
].deletion_time
);
2866 ASSERT_EQ(now2_delay
, entries
[id
].deferment_end_time
);
2868 ASSERT_EQ(0, trash_list(&ioctx
, id
, 1, &entries
));
2869 ASSERT_TRUE(entries
.empty());
2871 cls::rbd::TrashImageSpec spec_res1
;
2872 ASSERT_EQ(0, trash_get(&ioctx
, id
, &spec_res1
));
2873 cls::rbd::TrashImageSpec spec_res2
;
2874 ASSERT_EQ(0, trash_get(&ioctx
, id2
, &spec_res2
));
2876 ASSERT_EQ(spec_res1
.name
, "name2");
2877 ASSERT_EQ(spec_res1
.deletion_time
, now2
);
2878 ASSERT_EQ(spec_res1
.deferment_end_time
, now2_delay
);
2880 ASSERT_EQ(spec_res2
.name
, "name");
2881 ASSERT_EQ(spec_res2
.deletion_time
, now1
);
2882 ASSERT_EQ(spec_res2
.deferment_end_time
, now1_delay
);
2887 TEST_F(TestClsRbd
, op_features
)
2889 librados::IoCtx ioctx
;
2890 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2892 string oid
= get_temp_image_name();
2893 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
2895 uint64_t op_features
= RBD_OPERATION_FEATURE_CLONE_PARENT
;
2896 uint64_t mask
= ~RBD_OPERATION_FEATURES_ALL
;
2897 ASSERT_EQ(-EINVAL
, op_features_set(&ioctx
, oid
, op_features
, mask
));
2900 ASSERT_EQ(0, op_features_set(&ioctx
, oid
, op_features
, mask
));
2902 uint64_t actual_op_features
;
2903 ASSERT_EQ(0, op_features_get(&ioctx
, oid
, &actual_op_features
));
2904 ASSERT_EQ(0u, actual_op_features
);
2907 uint64_t incompatible_features
;
2908 ASSERT_EQ(0, get_features(&ioctx
, oid
, true, &features
,
2909 &incompatible_features
));
2910 ASSERT_EQ(0u, features
);
2912 op_features
= RBD_OPERATION_FEATURES_ALL
;
2913 mask
= RBD_OPERATION_FEATURES_ALL
;
2914 ASSERT_EQ(0, op_features_set(&ioctx
, oid
, op_features
, mask
));
2915 ASSERT_EQ(0, op_features_get(&ioctx
, oid
, &actual_op_features
));
2916 ASSERT_EQ(mask
, actual_op_features
);
2918 ASSERT_EQ(0, get_features(&ioctx
, oid
, true, &features
,
2919 &incompatible_features
));
2920 ASSERT_EQ(RBD_FEATURE_OPERATIONS
, features
);
2923 mask
= RBD_OPERATION_FEATURE_CLONE_PARENT
;
2924 ASSERT_EQ(0, op_features_set(&ioctx
, oid
, op_features
, mask
));
2925 ASSERT_EQ(0, op_features_get(&ioctx
, oid
, &actual_op_features
));
2927 uint64_t expected_op_features
= RBD_OPERATION_FEATURES_ALL
&
2928 ~RBD_OPERATION_FEATURE_CLONE_PARENT
;
2929 ASSERT_EQ(expected_op_features
, actual_op_features
);
2931 mask
= RBD_OPERATION_FEATURES_ALL
;
2932 ASSERT_EQ(0, op_features_set(&ioctx
, oid
, op_features
, mask
));
2933 ASSERT_EQ(0, get_features(&ioctx
, oid
, true, &features
,
2934 &incompatible_features
));
2935 ASSERT_EQ(0u, features
);
2938 TEST_F(TestClsRbd
, clone_parent
)
2940 librados::IoCtx ioctx
;
2941 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
2943 string oid
= get_temp_image_name();
2944 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
2945 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 123, "user_snap"));
2947 ASSERT_EQ(-ENOENT
, child_attach(&ioctx
, oid
, 345, {}));
2948 ASSERT_EQ(-ENOENT
, child_detach(&ioctx
, oid
, 123, {}));
2949 ASSERT_EQ(-ENOENT
, child_detach(&ioctx
, oid
, 345, {}));
2951 ASSERT_EQ(0, child_attach(&ioctx
, oid
, 123, {1, "", "image1"}));
2952 ASSERT_EQ(-EEXIST
, child_attach(&ioctx
, oid
, 123, {1, "", "image1"}));
2953 ASSERT_EQ(0, child_attach(&ioctx
, oid
, 123, {1, "", "image2"}));
2954 ASSERT_EQ(0, child_attach(&ioctx
, oid
, 123, {2, "", "image2"}));
2956 cls::rbd::SnapshotInfo snap
;
2957 ASSERT_EQ(0, snapshot_get(&ioctx
, oid
, 123, &snap
));
2958 ASSERT_EQ(3U, snap
.child_count
);
2960 // op feature should have been enabled
2961 uint64_t op_features
;
2962 uint64_t expected_op_features
= RBD_OPERATION_FEATURE_CLONE_PARENT
;
2963 ASSERT_EQ(0, op_features_get(&ioctx
, oid
, &op_features
));
2964 ASSERT_TRUE((op_features
& expected_op_features
) == expected_op_features
);
2966 // cannot attach to trashed snapshot
2967 librados::ObjectWriteOperation op1
;
2968 ::librbd::cls_client::snapshot_add(&op1
, 234, "trash_snap",
2969 cls::rbd::UserSnapshotNamespace());
2970 ASSERT_EQ(0, ioctx
.operate(oid
, &op1
));
2971 librados::ObjectWriteOperation op2
;
2972 ::librbd::cls_client::snapshot_trash_add(&op2
, 234);
2973 ASSERT_EQ(0, ioctx
.operate(oid
, &op2
));
2974 ASSERT_EQ(-ENOENT
, child_attach(&ioctx
, oid
, 234, {}));
2976 cls::rbd::ChildImageSpecs child_images
;
2977 ASSERT_EQ(0, children_list(&ioctx
, oid
, 123, &child_images
));
2979 cls::rbd::ChildImageSpecs expected_child_images
= {
2980 {1, "", "image1"}, {1, "", "image2"}, {2, "", "image2"}};
2981 ASSERT_EQ(expected_child_images
, child_images
);
2983 // move snapshot to the trash
2984 ASSERT_EQ(-EBUSY
, snapshot_remove(&ioctx
, oid
, 123));
2985 librados::ObjectWriteOperation op3
;
2986 ::librbd::cls_client::snapshot_trash_add(&op3
, 123);
2987 ASSERT_EQ(0, ioctx
.operate(oid
, &op3
));
2988 ASSERT_EQ(0, snapshot_get(&ioctx
, oid
, 123, &snap
));
2989 ASSERT_EQ(cls::rbd::SNAPSHOT_NAMESPACE_TYPE_TRASH
,
2990 cls::rbd::get_snap_namespace_type(snap
.snapshot_namespace
));
2992 expected_op_features
|= RBD_OPERATION_FEATURE_SNAP_TRASH
;
2993 ASSERT_EQ(0, op_features_get(&ioctx
, oid
, &op_features
));
2994 ASSERT_TRUE((op_features
& expected_op_features
) == expected_op_features
);
2996 expected_child_images
= {{1, "", "image1"}, {2, "", "image2"}};
2997 ASSERT_EQ(0, child_detach(&ioctx
, oid
, 123, {1, "", "image2"}));
2998 ASSERT_EQ(0, children_list(&ioctx
, oid
, 123, &child_images
));
2999 ASSERT_EQ(expected_child_images
, child_images
);
3001 ASSERT_EQ(0, child_detach(&ioctx
, oid
, 123, {2, "", "image2"}));
3003 ASSERT_EQ(0, op_features_get(&ioctx
, oid
, &op_features
));
3004 ASSERT_TRUE((op_features
& expected_op_features
) == expected_op_features
);
3006 ASSERT_EQ(0, child_detach(&ioctx
, oid
, 123, {1, "", "image1"}));
3007 ASSERT_EQ(-ENOENT
, children_list(&ioctx
, oid
, 123, &child_images
));
3009 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 234));
3010 ASSERT_EQ(0, op_features_get(&ioctx
, oid
, &op_features
));
3011 ASSERT_TRUE((op_features
& expected_op_features
) ==
3012 RBD_OPERATION_FEATURE_SNAP_TRASH
);
3014 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 123));
3015 ASSERT_EQ(0, op_features_get(&ioctx
, oid
, &op_features
));
3016 ASSERT_TRUE((op_features
& expected_op_features
) == 0);
3019 TEST_F(TestClsRbd
, clone_parent_ns
)
3021 librados::IoCtx ioctx
;
3022 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
3024 string oid
= get_temp_image_name();
3025 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
3026 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 123, "user_snap"));
3028 ASSERT_EQ(0, child_attach(&ioctx
, oid
, 123, {1, "ns1", "image1"}));
3029 ASSERT_EQ(-EEXIST
, child_attach(&ioctx
, oid
, 123, {1, "ns1", "image1"}));
3030 ASSERT_EQ(0, child_attach(&ioctx
, oid
, 123, {1, "ns2", "image1"}));
3032 cls::rbd::ChildImageSpecs child_images
;
3033 ASSERT_EQ(0, children_list(&ioctx
, oid
, 123, &child_images
));
3035 cls::rbd::ChildImageSpecs expected_child_images
= {
3036 {1, "ns1", "image1"}, {1, "ns2", "image1"}};
3037 ASSERT_EQ(expected_child_images
, child_images
);
3039 expected_child_images
= {{1, "ns1", "image1"}};
3040 ASSERT_EQ(0, child_detach(&ioctx
, oid
, 123, {1, "ns2", "image1"}));
3041 ASSERT_EQ(0, children_list(&ioctx
, oid
, 123, &child_images
));
3042 ASSERT_EQ(expected_child_images
, child_images
);
3044 ASSERT_EQ(0, child_detach(&ioctx
, oid
, 123, {1, "ns1", "image1"}));
3045 ASSERT_EQ(-ENOENT
, children_list(&ioctx
, oid
, 123, &child_images
));
3047 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 123));
3050 TEST_F(TestClsRbd
, clone_child
)
3052 librados::IoCtx ioctx
;
3053 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
3055 string oid
= get_temp_image_name();
3056 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22,
3057 RBD_FEATURE_LAYERING
| RBD_FEATURE_DEEP_FLATTEN
,
3059 ASSERT_EQ(0, set_parent(&ioctx
, oid
, {1, "", "parent", 2}, 1));
3060 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 123, "user_snap1"));
3061 ASSERT_EQ(0, op_features_set(&ioctx
, oid
, RBD_OPERATION_FEATURE_CLONE_CHILD
,
3062 RBD_OPERATION_FEATURE_CLONE_CHILD
));
3064 // clone child should be disabled due to deep flatten
3065 ASSERT_EQ(0, remove_parent(&ioctx
, oid
));
3066 uint64_t op_features
;
3067 ASSERT_EQ(0, op_features_get(&ioctx
, oid
, &op_features
));
3068 ASSERT_TRUE((op_features
& RBD_OPERATION_FEATURE_CLONE_CHILD
) == 0ULL);
3070 ASSERT_EQ(0, set_features(&ioctx
, oid
, 0, RBD_FEATURE_DEEP_FLATTEN
));
3071 ASSERT_EQ(0, set_parent(&ioctx
, oid
, {1, "", "parent", 2}, 1));
3072 ASSERT_EQ(0, snapshot_add(&ioctx
, oid
, 124, "user_snap2"));
3073 ASSERT_EQ(0, op_features_set(&ioctx
, oid
, RBD_OPERATION_FEATURE_CLONE_CHILD
,
3074 RBD_OPERATION_FEATURE_CLONE_CHILD
));
3076 // clone child should remain enabled w/o deep flatten
3077 ASSERT_EQ(0, remove_parent(&ioctx
, oid
));
3078 ASSERT_EQ(0, op_features_get(&ioctx
, oid
, &op_features
));
3079 ASSERT_TRUE((op_features
& RBD_OPERATION_FEATURE_CLONE_CHILD
) ==
3080 RBD_OPERATION_FEATURE_CLONE_CHILD
);
3082 // ... but removing the last linked snapshot should disable it
3083 ASSERT_EQ(0, snapshot_remove(&ioctx
, oid
, 124));
3084 ASSERT_EQ(0, op_features_get(&ioctx
, oid
, &op_features
));
3085 ASSERT_TRUE((op_features
& RBD_OPERATION_FEATURE_CLONE_CHILD
) == 0ULL);
3088 TEST_F(TestClsRbd
, namespace_methods
)
3090 librados::IoCtx ioctx
;
3091 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
3093 string name1
= "123456789";
3094 string name2
= "123456780";
3096 std::list
<std::string
> entries
;
3097 ASSERT_EQ(-ENOENT
, namespace_list(&ioctx
, "", 1024, &entries
));
3099 ASSERT_EQ(0, namespace_add(&ioctx
, name1
));
3100 ASSERT_EQ(-EEXIST
, namespace_add(&ioctx
, name1
));
3102 ASSERT_EQ(0, namespace_remove(&ioctx
, name1
));
3103 ASSERT_EQ(-ENOENT
, namespace_remove(&ioctx
, name1
));
3105 ASSERT_EQ(0, namespace_list(&ioctx
, "", 1024, &entries
));
3106 ASSERT_TRUE(entries
.empty());
3108 ASSERT_EQ(0, namespace_add(&ioctx
, name1
));
3109 ASSERT_EQ(0, namespace_add(&ioctx
, name2
));
3111 ASSERT_EQ(0, namespace_list(&ioctx
, "", 1, &entries
));
3112 ASSERT_EQ(1U, entries
.size());
3113 ASSERT_EQ(name2
, entries
.front());
3115 ASSERT_EQ(0, namespace_list(&ioctx
, name2
, 1, &entries
));
3116 ASSERT_EQ(1U, entries
.size());
3117 ASSERT_EQ(name1
, entries
.front());
3119 ASSERT_EQ(0, namespace_list(&ioctx
, name1
, 1, &entries
));
3120 ASSERT_TRUE(entries
.empty());
3123 TEST_F(TestClsRbd
, migration
)
3125 librados::IoCtx ioctx
;
3126 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
3128 string oid
= get_temp_image_name();
3129 ASSERT_EQ(0, create_image(&ioctx
, oid
, 0, 22, 0, oid
, -1));
3131 cls::rbd::MigrationSpec
migration_spec(cls::rbd::MIGRATION_HEADER_TYPE_DST
,
3133 "{\"format\": \"raw\"}", {}, 0, false,
3134 cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
,
3136 cls::rbd::MIGRATION_STATE_PREPARING
,
3138 cls::rbd::MigrationSpec read_migration_spec
;
3140 ASSERT_EQ(-EINVAL
, migration_get(&ioctx
, oid
, &read_migration_spec
));
3143 uint64_t incompatible_features
;
3144 ASSERT_EQ(0, get_features(&ioctx
, oid
, CEPH_NOSNAP
, &features
,
3145 &incompatible_features
));
3146 ASSERT_EQ(0U, features
);
3148 ASSERT_EQ(0, migration_set(&ioctx
, oid
, migration_spec
));
3149 ASSERT_EQ(0, migration_get(&ioctx
, oid
, &read_migration_spec
));
3150 ASSERT_EQ(migration_spec
, read_migration_spec
);
3152 ASSERT_EQ(0, get_features(&ioctx
, oid
, CEPH_NOSNAP
, &features
,
3153 &incompatible_features
));
3154 ASSERT_EQ(RBD_FEATURE_MIGRATING
, features
);
3156 ASSERT_EQ(-EEXIST
, migration_set(&ioctx
, oid
, migration_spec
));
3158 migration_spec
.state
= cls::rbd::MIGRATION_STATE_PREPARED
;
3159 migration_spec
.state_description
= "456";
3160 ASSERT_EQ(0, migration_set_state(&ioctx
, oid
, migration_spec
.state
,
3161 migration_spec
.state_description
));
3162 ASSERT_EQ(0, migration_get(&ioctx
, oid
, &read_migration_spec
));
3163 ASSERT_EQ(migration_spec
, read_migration_spec
);
3165 ASSERT_EQ(0, migration_remove(&ioctx
, oid
));
3167 ASSERT_EQ(0, get_features(&ioctx
, oid
, CEPH_NOSNAP
, &features
,
3168 &incompatible_features
));
3169 ASSERT_EQ(0U, features
);
3171 ASSERT_EQ(-EINVAL
, migration_get(&ioctx
, oid
, &read_migration_spec
));
3172 ASSERT_EQ(-EINVAL
, migration_set_state(&ioctx
, oid
, migration_spec
.state
,
3173 migration_spec
.state_description
));
3175 migration_spec
.header_type
= cls::rbd::MIGRATION_HEADER_TYPE_SRC
;
3177 ASSERT_EQ(0, migration_set(&ioctx
, oid
, migration_spec
));
3179 ASSERT_EQ(0, get_features(&ioctx
, oid
, CEPH_NOSNAP
, &features
,
3180 &incompatible_features
));
3181 ASSERT_EQ(RBD_FEATURE_MIGRATING
, features
);
3183 ASSERT_EQ(0, migration_remove(&ioctx
, oid
));
3185 ASSERT_EQ(-EINVAL
, migration_get(&ioctx
, oid
, &read_migration_spec
));
3186 ASSERT_EQ(0, get_features(&ioctx
, oid
, CEPH_NOSNAP
, &features
,
3187 &incompatible_features
));
3188 ASSERT_EQ(0U, features
);
3193 TEST_F(TestClsRbd
, migration_v1
)
3195 librados::IoCtx ioctx
;
3196 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
3199 header
.append(RBD_HEADER_TEXT
, sizeof(RBD_HEADER_TEXT
));
3200 string oid
= get_temp_image_name();
3201 ASSERT_EQ(0, ioctx
.write(oid
, header
, header
.length(), 0));
3203 cls::rbd::MigrationSpec
migration_spec(cls::rbd::MIGRATION_HEADER_TYPE_DST
, 1,
3204 "name", "ns", "id", "", {}, 0, false,
3205 cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
,
3207 cls::rbd::MIGRATION_STATE_PREPARING
,
3209 cls::rbd::MigrationSpec read_migration_spec
;
3211 ASSERT_EQ(-EINVAL
, migration_get(&ioctx
, oid
, &read_migration_spec
));
3213 // v1 format image can only be migration source
3214 ASSERT_EQ(-EINVAL
, migration_set(&ioctx
, oid
, migration_spec
));
3216 migration_spec
.header_type
= cls::rbd::MIGRATION_HEADER_TYPE_SRC
;
3217 ASSERT_EQ(0, migration_set(&ioctx
, oid
, migration_spec
));
3219 ASSERT_EQ(0, migration_get(&ioctx
, oid
, &read_migration_spec
));
3220 ASSERT_EQ(migration_spec
, read_migration_spec
);
3223 ASSERT_EQ(static_cast<int>(sizeof(RBD_MIGRATE_HEADER_TEXT
)),
3224 ioctx
.read(oid
, header
, sizeof(RBD_MIGRATE_HEADER_TEXT
), 0));
3225 ASSERT_STREQ(RBD_MIGRATE_HEADER_TEXT
, header
.c_str());
3227 ASSERT_EQ(-EEXIST
, migration_set(&ioctx
, oid
, migration_spec
));
3229 migration_spec
.state
= cls::rbd::MIGRATION_STATE_PREPARED
;
3230 migration_spec
.state_description
= "456";
3231 ASSERT_EQ(0, migration_set_state(&ioctx
, oid
, migration_spec
.state
,
3232 migration_spec
.state_description
));
3233 ASSERT_EQ(0, migration_get(&ioctx
, oid
, &read_migration_spec
));
3234 ASSERT_EQ(migration_spec
, read_migration_spec
);
3236 ASSERT_EQ(0, migration_remove(&ioctx
, oid
));
3238 ASSERT_EQ(-EINVAL
, migration_get(&ioctx
, oid
, &read_migration_spec
));
3239 ASSERT_EQ(-EINVAL
, migration_set_state(&ioctx
, oid
, migration_spec
.state
,
3240 migration_spec
.state_description
));
3242 ASSERT_EQ(static_cast<int>(sizeof(RBD_HEADER_TEXT
)),
3243 ioctx
.read(oid
, header
, sizeof(RBD_HEADER_TEXT
), 0));
3244 ASSERT_STREQ(RBD_HEADER_TEXT
, header
.c_str());
3249 TEST_F(TestClsRbd
, assert_snapc_seq
)
3251 librados::IoCtx ioctx
;
3252 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
3254 string oid
= get_temp_image_name();
3257 assert_snapc_seq(&ioctx
, oid
, 0,
3258 cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ
));
3260 assert_snapc_seq(&ioctx
, oid
, 0,
3261 cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ
));
3263 ASSERT_EQ(0, ioctx
.create(oid
, true));
3265 uint64_t snapc_seq
= 0;
3268 assert_snapc_seq(&ioctx
, oid
, snapc_seq
,
3269 cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ
));
3271 assert_snapc_seq(&ioctx
, oid
, snapc_seq
,
3272 cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ
));
3274 std::vector
<uint64_t> snaps
;
3275 snaps
.push_back(CEPH_NOSNAP
);
3276 ASSERT_EQ(0, ioctx
.selfmanaged_snap_create(&snaps
.back()));
3277 snapc_seq
= snaps
[0];
3280 assert_snapc_seq(&ioctx
, oid
, snapc_seq
,
3281 cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ
));
3283 assert_snapc_seq(&ioctx
, oid
, snapc_seq
,
3284 cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ
));
3286 ASSERT_EQ(0, ioctx
.selfmanaged_snap_set_write_ctx(snaps
[0], snaps
));
3289 ASSERT_EQ(0, ioctx
.write(oid
, bl
, bl
.length(), 0));
3292 assert_snapc_seq(&ioctx
, oid
, snapc_seq
,
3293 cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ
));
3295 assert_snapc_seq(&ioctx
, oid
, snapc_seq
,
3296 cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ
));
3299 assert_snapc_seq(&ioctx
, oid
, snapc_seq
+ 1,
3300 cls::rbd::ASSERT_SNAPC_SEQ_GT_SNAPSET_SEQ
));
3302 assert_snapc_seq(&ioctx
, oid
, snapc_seq
+ 1,
3303 cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ
));
3305 ASSERT_EQ(0, ioctx
.selfmanaged_snap_remove(snapc_seq
));
3308 TEST_F(TestClsRbd
, sparsify
)
3310 librados::IoCtx ioctx
;
3311 ASSERT_EQ(0, _rados
.ioctx_create(_pool_name
.c_str(), ioctx
));
3313 string oid
= get_temp_image_name();
3316 bool sparse_read_supported
= is_sparse_read_supported(ioctx
, oid
);
3318 // test sparsify on a non-existent object
3320 ASSERT_EQ(-ENOENT
, sparsify(&ioctx
, oid
, 16, false));
3322 ASSERT_EQ(-ENOENT
, ioctx
.stat(oid
, &size
, NULL
));
3323 ASSERT_EQ(-ENOENT
, sparsify(&ioctx
, oid
, 16, true));
3324 ASSERT_EQ(-ENOENT
, ioctx
.stat(oid
, &size
, NULL
));
3326 // test sparsify on an empty object
3328 ASSERT_EQ(0, ioctx
.create(oid
, true));
3329 ASSERT_EQ(0, sparsify(&ioctx
, oid
, 16, false));
3330 ASSERT_EQ(0, sparsify(&ioctx
, oid
, 16, true));
3331 ASSERT_EQ(-ENOENT
, sparsify(&ioctx
, oid
, 16, false));
3333 // test sparsify on a zeroed object
3336 inbl
.append(std::string(4096, '\0'));
3337 ASSERT_EQ(0, ioctx
.write(oid
, inbl
, inbl
.length(), 0));
3338 ASSERT_EQ(0, sparsify(&ioctx
, oid
, 16, false));
3339 std::map
<uint64_t, uint64_t> m
;
3341 std::map
<uint64_t, uint64_t> expected_m
;
3342 bufferlist expected_outbl
;
3343 switch (int r
= ioctx
.sparse_read(oid
, m
, outbl
, inbl
.length(), 0); r
) {
3346 ASSERT_EQ(expected_m
, m
);
3349 expected_m
= {{0, 0}};
3350 ASSERT_EQ(expected_m
, m
);
3353 FAIL() << r
<< " is odd";
3355 ASSERT_EQ(m
, expected_m
);
3356 ASSERT_EQ(0, sparsify(&ioctx
, oid
, 16, true));
3357 ASSERT_EQ(-ENOENT
, sparsify(&ioctx
, oid
, 16, true));
3358 ASSERT_EQ(0, ioctx
.write(oid
, inbl
, inbl
.length(), 0));
3359 ASSERT_EQ(0, sparsify(&ioctx
, oid
, 16, true));
3360 ASSERT_EQ(-ENOENT
, sparsify(&ioctx
, oid
, 16, true));
3362 // test sparsify on an object with zeroes
3364 inbl
.append(std::string(4096, '1'));
3365 inbl
.append(std::string(4096, '\0'));
3366 inbl
.append(std::string(4096, '2'));
3367 inbl
.append(std::string(4096, '\0'));
3368 ASSERT_EQ(0, ioctx
.write(oid
, inbl
, inbl
.length(), 0));
3370 // try to sparsify with sparse_size too large
3372 ASSERT_EQ(0, sparsify(&ioctx
, oid
, inbl
.length(), true));
3373 expected_m
= {{0, inbl
.length()}};
3374 expected_outbl
= inbl
;
3375 ASSERT_EQ((int)expected_m
.size(),
3376 ioctx
.sparse_read(oid
, m
, outbl
, inbl
.length(), 0));
3377 ASSERT_EQ(m
, expected_m
);
3378 ASSERT_TRUE(outbl
.contents_equal(expected_outbl
));
3380 // sparsify with small sparse_size
3382 ASSERT_EQ(0, sparsify(&ioctx
, oid
, 16, true));
3384 ASSERT_EQ((int)(inbl
.length() - 4096),
3385 ioctx
.read(oid
, outbl
, inbl
.length(), 0));
3386 outbl
.append(std::string(4096, '\0'));
3387 ASSERT_TRUE(outbl
.contents_equal(expected_outbl
));
3388 if (sparse_read_supported
) {
3389 expected_m
= {{4096 * 1, 4096}, {4096 * 3, 4096}};
3390 expected_outbl
.clear();
3391 expected_outbl
.append(std::string(4096, '1'));
3392 expected_outbl
.append(std::string(4096, '2'));
3394 expected_m
= {{0, 4 * 4096}};
3395 expected_outbl
.clear();
3396 expected_outbl
.append(std::string(4096, '\0'));
3397 expected_outbl
.append(std::string(4096, '1'));
3398 expected_outbl
.append(std::string(4096, '\0'));
3399 expected_outbl
.append(std::string(4096, '2'));
3403 ASSERT_EQ((int)expected_m
.size(),
3404 ioctx
.sparse_read(oid
, m
, outbl
, inbl
.length(), 0));
3405 ASSERT_EQ(m
, expected_m
);
3406 ASSERT_TRUE(outbl
.contents_equal(expected_outbl
));
3408 // test it is the same after yet another sparsify
3410 ASSERT_EQ(0, sparsify(&ioctx
, oid
, 16, true));
3413 ASSERT_EQ((int)expected_m
.size(),
3414 ioctx
.sparse_read(oid
, m
, outbl
, inbl
.length(), 0));
3415 ASSERT_EQ(m
, expected_m
);
3416 ASSERT_TRUE(outbl
.contents_equal(expected_outbl
));
3418 ASSERT_EQ(0, ioctx
.remove(oid
));