]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/test_internal.cc
import ceph 15.2.10
[ceph.git] / ceph / src / test / librbd / test_internal.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
11fdf7f2
TL
4#include "cls/journal/cls_journal_client.h"
5#include "cls/rbd/cls_rbd_client.h"
7c673cae
FG
6#include "cls/rbd/cls_rbd_types.h"
7#include "test/librbd/test_fixture.h"
8#include "test/librbd/test_support.h"
9#include "include/rbd/librbd.h"
10#include "librbd/ExclusiveLock.h"
11#include "librbd/ImageState.h"
12#include "librbd/ImageWatcher.h"
13#include "librbd/internal.h"
14#include "librbd/ObjectMap.h"
15#include "librbd/Operations.h"
16#include "librbd/api/DiffIterate.h"
11fdf7f2 17#include "librbd/api/Image.h"
494da23a 18#include "librbd/api/Migration.h"
11fdf7f2 19#include "librbd/api/PoolMetadata.h"
9f95a23c 20#include "librbd/api/Snapshot.h"
7c673cae
FG
21#include "librbd/io/AioCompletion.h"
22#include "librbd/io/ImageRequest.h"
23#include "librbd/io/ImageRequestWQ.h"
24#include "osdc/Striper.h"
9f95a23c 25#include "common/Cond.h"
7c673cae 26#include <boost/scope_exit.hpp>
d2e6a577 27#include <boost/algorithm/string/predicate.hpp>
7c673cae
FG
28#include <boost/assign/list_of.hpp>
29#include <utility>
30#include <vector>
31
32void register_test_internal() {
33}
34
35class TestInternal : public TestFixture {
36public:
37
38 TestInternal() {}
39
40 typedef std::vector<std::pair<std::string, bool> > Snaps;
41
42 void TearDown() override {
43 unlock_image();
44 for (Snaps::iterator iter = m_snaps.begin(); iter != m_snaps.end(); ++iter) {
45 librbd::ImageCtx *ictx;
46 EXPECT_EQ(0, open_image(m_image_name, &ictx));
47 if (iter->second) {
48 EXPECT_EQ(0,
49 ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(),
50 iter->first.c_str()));
51 }
52 EXPECT_EQ(0,
53 ictx->operations->snap_remove(cls::rbd::UserSnapshotNamespace(),
54 iter->first.c_str()));
55 }
56
57 TestFixture::TearDown();
58 }
59
60 int create_snapshot(const char *snap_name, bool snap_protect) {
61 librbd::ImageCtx *ictx;
62 int r = open_image(m_image_name, &ictx);
63 if (r < 0) {
64 return r;
65 }
66
67 r = snap_create(*ictx, snap_name);
68 if (r < 0) {
69 return r;
70 }
71
72 m_snaps.push_back(std::make_pair(snap_name, snap_protect));
73 if (snap_protect) {
74 r = ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(), snap_name);
75 if (r < 0) {
76 return r;
77 }
78 }
79 close_image(ictx);
80 return 0;
81 }
82
83 Snaps m_snaps;
84};
85
86class DummyContext : public Context {
87public:
88 void finish(int r) override {
89 }
90};
91
92void generate_random_iomap(librbd::Image &image, int num_objects, int object_size,
93 int max_count, map<uint64_t, uint64_t> &iomap)
94{
95 uint64_t stripe_unit, stripe_count;
96
97 stripe_unit = image.get_stripe_unit();
98 stripe_count = image.get_stripe_count();
99
100 while (max_count-- > 0) {
101 // generate random image offset based on base random object
102 // number and object offset and then map that back to an
103 // object number based on stripe unit and count.
104 uint64_t ono = rand() % num_objects;
105 uint64_t offset = rand() % (object_size - TEST_IO_SIZE);
106 uint64_t imageoff = (ono * object_size) + offset;
107
108 file_layout_t layout;
109 layout.object_size = object_size;
110 layout.stripe_unit = stripe_unit;
111 layout.stripe_count = stripe_count;
112
113 vector<ObjectExtent> ex;
114 Striper::file_to_extents(g_ceph_context, 1, &layout, imageoff, TEST_IO_SIZE, 0, ex);
115
116 // lets not worry if IO spans multiple extents (>1 object). in such
117 // as case we would perform the write multiple times to the same
118 // offset, but we record all objects that would be generated with
119 // this IO. TODO: fix this if such a need is required by your
120 // test.
121 vector<ObjectExtent>::iterator it;
122 map<uint64_t, uint64_t> curr_iomap;
123 for (it = ex.begin(); it != ex.end(); ++it) {
124 if (iomap.find((*it).objectno) != iomap.end()) {
125 break;
126 }
127
128 curr_iomap.insert(make_pair((*it).objectno, imageoff));
129 }
130
131 if (it == ex.end()) {
132 iomap.insert(curr_iomap.begin(), curr_iomap.end());
133 }
134 }
135}
136
11fdf7f2
TL
137static bool is_sparsify_supported(librados::IoCtx &ioctx,
138 const std::string &oid) {
139 EXPECT_EQ(0, ioctx.create(oid, true));
140 int r = librbd::cls_client::sparsify(&ioctx, oid, 16, true);
141 EXPECT_TRUE(r == 0 || r == -EOPNOTSUPP);
142 ioctx.remove(oid);
143
144 return (r == 0);
145}
146
147static bool is_sparse_read_supported(librados::IoCtx &ioctx,
148 const std::string &oid) {
149 EXPECT_EQ(0, ioctx.create(oid, true));
150 bufferlist inbl;
151 inbl.append(std::string(1, 'X'));
152 EXPECT_EQ(0, ioctx.write(oid, inbl, inbl.length(), 1));
153 EXPECT_EQ(0, ioctx.write(oid, inbl, inbl.length(), 3));
154
155 std::map<uint64_t, uint64_t> m;
156 bufferlist outbl;
157 int r = ioctx.sparse_read(oid, m, outbl, 4, 0);
158 ioctx.remove(oid);
159
160 int expected_r = 2;
161 std::map<uint64_t, uint64_t> expected_m = {{1, 1}, {3, 1}};
162 bufferlist expected_outbl;
163 expected_outbl.append(std::string(2, 'X'));
164
165 return (r == expected_r && m == expected_m &&
166 outbl.contents_equal(expected_outbl));
167}
168
7c673cae
FG
169TEST_F(TestInternal, OpenByID) {
170 REQUIRE_FORMAT_V2();
171
172 librbd::ImageCtx *ictx;
173 ASSERT_EQ(0, open_image(m_image_name, &ictx));
174 std::string id = ictx->id;
175 close_image(ictx);
176
177 ictx = new librbd::ImageCtx("", id, nullptr, m_ioctx, true);
11fdf7f2 178 ASSERT_EQ(0, ictx->state->open(0));
7c673cae
FG
179 ASSERT_EQ(ictx->name, m_image_name);
180 close_image(ictx);
181}
182
11fdf7f2
TL
183TEST_F(TestInternal, OpenSnapDNE) {
184 librbd::ImageCtx *ictx;
185 ASSERT_EQ(0, open_image(m_image_name, &ictx));
186
187 ictx = new librbd::ImageCtx(m_image_name, "", "unknown_snap", m_ioctx, true);
188 ASSERT_EQ(-ENOENT, ictx->state->open(librbd::OPEN_FLAG_SKIP_OPEN_PARENT));
189}
190
7c673cae
FG
191TEST_F(TestInternal, IsExclusiveLockOwner) {
192 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
193
194 librbd::ImageCtx *ictx;
195 ASSERT_EQ(0, open_image(m_image_name, &ictx));
196
197 bool is_owner;
198 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner));
199 ASSERT_FALSE(is_owner);
200
201 C_SaferCond ctx;
202 {
9f95a23c 203 std::unique_lock l{ictx->owner_lock};
7c673cae
FG
204 ictx->exclusive_lock->try_acquire_lock(&ctx);
205 }
206 ASSERT_EQ(0, ctx.wait());
207 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner));
208 ASSERT_TRUE(is_owner);
209}
210
211TEST_F(TestInternal, ResizeLocksImage) {
212 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
213
214 librbd::ImageCtx *ictx;
215 ASSERT_EQ(0, open_image(m_image_name, &ictx));
216
217 librbd::NoOpProgressContext no_op;
218 ASSERT_EQ(0, ictx->operations->resize(m_image_size >> 1, true, no_op));
219
220 bool is_owner;
221 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner));
222 ASSERT_TRUE(is_owner);
223}
224
225TEST_F(TestInternal, ResizeFailsToLockImage) {
226 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
227
228 librbd::ImageCtx *ictx;
229 ASSERT_EQ(0, open_image(m_image_name, &ictx));
230 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE, "manually locked"));
231
232 librbd::NoOpProgressContext no_op;
233 ASSERT_EQ(-EROFS, ictx->operations->resize(m_image_size >> 1, true, no_op));
234}
235
236TEST_F(TestInternal, SnapCreateLocksImage) {
237 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
238
239 librbd::ImageCtx *ictx;
240 ASSERT_EQ(0, open_image(m_image_name, &ictx));
241
242 ASSERT_EQ(0, snap_create(*ictx, "snap1"));
243 BOOST_SCOPE_EXIT( (ictx) ) {
244 ASSERT_EQ(0,
245 ictx->operations->snap_remove(cls::rbd::UserSnapshotNamespace(),
246 "snap1"));
247 } BOOST_SCOPE_EXIT_END;
248
249 bool is_owner;
250 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner));
251 ASSERT_TRUE(is_owner);
252}
253
254TEST_F(TestInternal, SnapCreateFailsToLockImage) {
255 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
256
257 librbd::ImageCtx *ictx;
258 ASSERT_EQ(0, open_image(m_image_name, &ictx));
259 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE, "manually locked"));
260
261 ASSERT_EQ(-EROFS, snap_create(*ictx, "snap1"));
262}
263
264TEST_F(TestInternal, SnapRollbackLocksImage) {
265 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
266
267 ASSERT_EQ(0, create_snapshot("snap1", false));
268
269 librbd::ImageCtx *ictx;
270 ASSERT_EQ(0, open_image(m_image_name, &ictx));
271
272 librbd::NoOpProgressContext no_op;
273 ASSERT_EQ(0, ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(),
274 "snap1",
275 no_op));
276
277 bool is_owner;
278 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner));
279 ASSERT_TRUE(is_owner);
280}
281
282TEST_F(TestInternal, SnapRollbackFailsToLockImage) {
283 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
284
285
286 ASSERT_EQ(0, create_snapshot("snap1", false));
287
288 librbd::ImageCtx *ictx;
289 ASSERT_EQ(0, open_image(m_image_name, &ictx));
290 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE, "manually locked"));
291
292 librbd::NoOpProgressContext no_op;
293 ASSERT_EQ(-EROFS,
294 ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(),
295 "snap1",
296 no_op));
297}
298
299TEST_F(TestInternal, SnapSetReleasesLock) {
300 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
301
302 ASSERT_EQ(0, create_snapshot("snap1", false));
303
304 librbd::ImageCtx *ictx;
305 ASSERT_EQ(0, open_image(m_image_name, &ictx));
11fdf7f2
TL
306 ASSERT_EQ(0, librbd::api::Image<>::snap_set(
307 ictx, cls::rbd::UserSnapshotNamespace(), "snap1"));
7c673cae
FG
308
309 bool is_owner;
310 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner));
311 ASSERT_FALSE(is_owner);
312}
313
314TEST_F(TestInternal, FlattenLocksImage) {
315 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_LAYERING);
316
317 ASSERT_EQ(0, create_snapshot("snap1", true));
318
319 librbd::ImageCtx *ictx;
320 ASSERT_EQ(0, open_image(m_image_name, &ictx));
321
322 uint64_t features;
323 ASSERT_EQ(0, librbd::get_features(ictx, &features));
324
325 std::string clone_name = get_temp_image_name();
326 int order = ictx->order;
327 ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap1", m_ioctx,
328 clone_name.c_str(), features, &order, 0, 0));
329
330 librbd::ImageCtx *ictx2;
331 ASSERT_EQ(0, open_image(clone_name, &ictx2));
332
333 librbd::NoOpProgressContext no_op;
334 ASSERT_EQ(0, ictx2->operations->flatten(no_op));
335
336 bool is_owner;
337 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx2, &is_owner));
338 ASSERT_TRUE(is_owner);
339}
340
341TEST_F(TestInternal, FlattenFailsToLockImage) {
342 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_LAYERING);
343
344 ASSERT_EQ(0, create_snapshot("snap1", true));
345
346 librbd::ImageCtx *ictx;
347 ASSERT_EQ(0, open_image(m_image_name, &ictx));
348
349 uint64_t features;
350 ASSERT_EQ(0, librbd::get_features(ictx, &features));
351
352 std::string clone_name = get_temp_image_name();
353 int order = ictx->order;
354 ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap1", m_ioctx,
355 clone_name.c_str(), features, &order, 0, 0));
356
357 TestInternal *parent = this;
358 librbd::ImageCtx *ictx2 = NULL;
359 BOOST_SCOPE_EXIT( (&m_ioctx) (clone_name) (parent) (&ictx2) ) {
360 if (ictx2 != NULL) {
361 parent->close_image(ictx2);
362 parent->unlock_image();
363 }
364 librbd::NoOpProgressContext no_op;
11fdf7f2 365 ASSERT_EQ(0, librbd::api::Image<>::remove(m_ioctx, clone_name, no_op));
7c673cae
FG
366 } BOOST_SCOPE_EXIT_END;
367
368 ASSERT_EQ(0, open_image(clone_name, &ictx2));
369 ASSERT_EQ(0, lock_image(*ictx2, LOCK_EXCLUSIVE, "manually locked"));
370
371 librbd::NoOpProgressContext no_op;
372 ASSERT_EQ(-EROFS, ictx2->operations->flatten(no_op));
373}
374
375TEST_F(TestInternal, AioWriteRequestsLock) {
376 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
377
378 librbd::ImageCtx *ictx;
379 ASSERT_EQ(0, open_image(m_image_name, &ictx));
380 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE, "manually locked"));
381
382 std::string buffer(256, '1');
383 Context *ctx = new DummyContext();
384 auto c = librbd::io::AioCompletion::create(ctx);
385 c->get();
386
387 bufferlist bl;
388 bl.append(buffer);
389 ictx->io_work_queue->aio_write(c, 0, buffer.size(), std::move(bl), 0);
390
391 bool is_owner;
392 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner));
393 ASSERT_FALSE(is_owner);
394 ASSERT_FALSE(c->is_complete());
395
396 unlock_image();
397 ASSERT_EQ(0, c->wait_for_complete());
398 c->put();
399}
400
401TEST_F(TestInternal, AioDiscardRequestsLock) {
402 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
403
404 librbd::ImageCtx *ictx;
405 ASSERT_EQ(0, open_image(m_image_name, &ictx));
406 ASSERT_EQ(0, lock_image(*ictx, LOCK_EXCLUSIVE, "manually locked"));
407
408 Context *ctx = new DummyContext();
409 auto c = librbd::io::AioCompletion::create(ctx);
410 c->get();
411 ictx->io_work_queue->aio_discard(c, 0, 256, false);
412
413 bool is_owner;
414 ASSERT_EQ(0, librbd::is_exclusive_lock_owner(ictx, &is_owner));
415 ASSERT_FALSE(is_owner);
416 ASSERT_FALSE(c->is_complete());
417
418 unlock_image();
419 ASSERT_EQ(0, c->wait_for_complete());
420 c->put();
421}
422
423TEST_F(TestInternal, CancelAsyncResize) {
424 REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
425
426 librbd::ImageCtx *ictx;
427 ASSERT_EQ(0, open_image(m_image_name, &ictx));
428
429 C_SaferCond ctx;
430 {
9f95a23c 431 std::unique_lock l{ictx->owner_lock};
7c673cae
FG
432 ictx->exclusive_lock->try_acquire_lock(&ctx);
433 }
434
435 ASSERT_EQ(0, ctx.wait());
436 {
9f95a23c 437 std::shared_lock owner_locker{ictx->owner_lock};
7c673cae
FG
438 ASSERT_TRUE(ictx->exclusive_lock->is_lock_owner());
439 }
440
441 uint64_t size;
442 ASSERT_EQ(0, librbd::get_size(ictx, &size));
443
444 uint32_t attempts = 0;
445 while (attempts++ < 20 && size > 0) {
446 C_SaferCond ctx;
447 librbd::NoOpProgressContext prog_ctx;
448
11fdf7f2 449 size -= std::min<uint64_t>(size, 1 << 18);
7c673cae 450 {
9f95a23c 451 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
452 ictx->operations->execute_resize(size, true, prog_ctx, &ctx, 0);
453 }
454
455 // try to interrupt the in-progress resize
456 ictx->cancel_async_requests();
457
458 int r = ctx.wait();
459 if (r == -ERESTART) {
460 std::cout << "detected canceled async request" << std::endl;
461 break;
462 }
463 ASSERT_EQ(0, r);
464 }
465}
466
467TEST_F(TestInternal, MultipleResize) {
468 librbd::ImageCtx *ictx;
469 ASSERT_EQ(0, open_image(m_image_name, &ictx));
470
471 if (ictx->exclusive_lock != nullptr) {
472 C_SaferCond ctx;
473 {
9f95a23c 474 std::unique_lock l{ictx->owner_lock};
7c673cae
FG
475 ictx->exclusive_lock->try_acquire_lock(&ctx);
476 }
477
9f95a23c 478 std::shared_lock owner_locker{ictx->owner_lock};
7c673cae
FG
479 ASSERT_EQ(0, ctx.wait());
480 ASSERT_TRUE(ictx->exclusive_lock->is_lock_owner());
481 }
482
483 uint64_t size;
484 ASSERT_EQ(0, librbd::get_size(ictx, &size));
485 uint64_t original_size = size;
486
487 std::vector<C_SaferCond*> contexts;
488
489 uint32_t attempts = 0;
490 librbd::NoOpProgressContext prog_ctx;
491 while (size > 0) {
492 uint64_t new_size = original_size;
493 if (attempts++ % 2 == 0) {
11fdf7f2 494 size -= std::min<uint64_t>(size, 1 << 18);
7c673cae
FG
495 new_size = size;
496 }
497
9f95a23c 498 std::shared_lock l{ictx->owner_lock};
7c673cae
FG
499 contexts.push_back(new C_SaferCond());
500 ictx->operations->execute_resize(new_size, true, prog_ctx, contexts.back(), 0);
501 }
502
503 for (uint32_t i = 0; i < contexts.size(); ++i) {
504 ASSERT_EQ(0, contexts[i]->wait());
505 delete contexts[i];
506 }
507
508 ASSERT_EQ(0, librbd::get_size(ictx, &size));
509 ASSERT_EQ(0U, size);
510}
511
512TEST_F(TestInternal, Metadata) {
513 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
514
515 map<string, bool> test_confs = boost::assign::map_list_of(
516 "aaaaaaa", false)(
517 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", false)(
518 "cccccccccccccc", false);
519 map<string, bool>::iterator it = test_confs.begin();
520 int r;
521 librbd::ImageCtx *ictx;
522 ASSERT_EQ(0, open_image(m_image_name, &ictx));
523
524 r = ictx->operations->metadata_set(it->first, "value1");
525 ASSERT_EQ(0, r);
526 ++it;
527 r = ictx->operations->metadata_set(it->first, "value2");
528 ASSERT_EQ(0, r);
529 ++it;
530 r = ictx->operations->metadata_set(it->first, "value3");
531 ASSERT_EQ(0, r);
532 r = ictx->operations->metadata_set("abcd", "value4");
533 ASSERT_EQ(0, r);
534 r = ictx->operations->metadata_set("xyz", "value5");
535 ASSERT_EQ(0, r);
536 map<string, bufferlist> pairs;
537 r = librbd::metadata_list(ictx, "", 0, &pairs);
538 ASSERT_EQ(0, r);
539 ASSERT_EQ(5u, pairs.size());
540 r = ictx->operations->metadata_remove("abcd");
541 ASSERT_EQ(0, r);
542 r = ictx->operations->metadata_remove("xyz");
543 ASSERT_EQ(0, r);
544 pairs.clear();
545 r = librbd::metadata_list(ictx, "", 0, &pairs);
546 ASSERT_EQ(0, r);
547 ASSERT_EQ(3u, pairs.size());
548 string val;
549 r = librbd::metadata_get(ictx, it->first, &val);
550 ASSERT_EQ(0, r);
551 ASSERT_STREQ(val.c_str(), "value3");
552}
553
11fdf7f2 554TEST_F(TestInternal, MetadataConfApply) {
7c673cae
FG
555 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
556
7c673cae
FG
557 librbd::ImageCtx *ictx;
558 ASSERT_EQ(0, open_image(m_image_name, &ictx));
559
11fdf7f2
TL
560 ASSERT_EQ(-ENOENT, ictx->operations->metadata_remove("conf_rbd_cache"));
561
562 bool cache = ictx->cache;
563 std::string rbd_conf_cache = cache ? "true" : "false";
564 std::string new_rbd_conf_cache = !cache ? "true" : "false";
565
566 ASSERT_EQ(0, ictx->operations->metadata_set("conf_rbd_cache",
567 new_rbd_conf_cache));
568 ASSERT_EQ(!cache, ictx->cache);
569
570 ASSERT_EQ(0, ictx->operations->metadata_remove("conf_rbd_cache"));
571 ASSERT_EQ(cache, ictx->cache);
7c673cae
FG
572}
573
574TEST_F(TestInternal, SnapshotCopyup)
575{
576 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
577
578 librbd::ImageCtx *ictx;
579 ASSERT_EQ(0, open_image(m_image_name, &ictx));
580
9f95a23c
TL
581 bool sparse_read_supported = is_sparse_read_supported(
582 ictx->data_ctx, ictx->get_object_name(10));
583
7c673cae
FG
584 bufferlist bl;
585 bl.append(std::string(256, '1'));
586 ASSERT_EQ(256, ictx->io_work_queue->write(0, bl.length(), bufferlist{bl}, 0));
9f95a23c
TL
587 ASSERT_EQ(256, ictx->io_work_queue->write(1024, bl.length(), bufferlist{bl},
588 0));
7c673cae
FG
589
590 ASSERT_EQ(0, snap_create(*ictx, "snap1"));
591 ASSERT_EQ(0,
592 ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
593 "snap1"));
594
595 uint64_t features;
596 ASSERT_EQ(0, librbd::get_features(ictx, &features));
597
598 std::string clone_name = get_temp_image_name();
599 int order = ictx->order;
600 ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap1", m_ioctx,
601 clone_name.c_str(), features, &order, 0, 0));
602
603 librbd::ImageCtx *ictx2;
604 ASSERT_EQ(0, open_image(clone_name, &ictx2));
605
606 ASSERT_EQ(0, snap_create(*ictx2, "snap1"));
607 ASSERT_EQ(0, snap_create(*ictx2, "snap2"));
608
609 ASSERT_EQ(256, ictx2->io_work_queue->write(256, bl.length(), bufferlist{bl},
610 0));
611
612 librados::IoCtx snap_ctx;
613 snap_ctx.dup(ictx2->data_ctx);
614 snap_ctx.snap_set_read(CEPH_SNAPDIR);
615
616 librados::snap_set_t snap_set;
617 ASSERT_EQ(0, snap_ctx.list_snaps(ictx2->get_object_name(0), &snap_set));
618
9f95a23c 619 uint64_t copyup_end = ictx2->enable_sparse_copyup ? 1024 + 256 : 1 << order;
7c673cae
FG
620 std::vector< std::pair<uint64_t,uint64_t> > expected_overlap =
621 boost::assign::list_of(
622 std::make_pair(0, 256))(
9f95a23c 623 std::make_pair(512, copyup_end - 512));
7c673cae
FG
624 ASSERT_EQ(2U, snap_set.clones.size());
625 ASSERT_NE(CEPH_NOSNAP, snap_set.clones[0].cloneid);
626 ASSERT_EQ(2U, snap_set.clones[0].snaps.size());
627 ASSERT_EQ(expected_overlap, snap_set.clones[0].overlap);
628 ASSERT_EQ(CEPH_NOSNAP, snap_set.clones[1].cloneid);
629
630 bufferptr read_ptr(256);
631 bufferlist read_bl;
632 read_bl.push_back(read_ptr);
633
634 std::list<std::string> snaps = {"snap1", "snap2", ""};
635 librbd::io::ReadResult read_result{&read_bl};
636 for (std::list<std::string>::iterator it = snaps.begin();
637 it != snaps.end(); ++it) {
638 const char *snap_name = it->empty() ? NULL : it->c_str();
11fdf7f2
TL
639 ASSERT_EQ(0, librbd::api::Image<>::snap_set(
640 ictx2, cls::rbd::UserSnapshotNamespace(), snap_name));
7c673cae
FG
641
642 ASSERT_EQ(256,
643 ictx2->io_work_queue->read(0, 256,
644 librbd::io::ReadResult{read_result},
645 0));
646 ASSERT_TRUE(bl.contents_equal(read_bl));
647
9f95a23c
TL
648 ASSERT_EQ(256,
649 ictx2->io_work_queue->read(1024, 256,
650 librbd::io::ReadResult{read_result},
651 0));
652 ASSERT_TRUE(bl.contents_equal(read_bl));
653
7c673cae
FG
654 ASSERT_EQ(256,
655 ictx2->io_work_queue->read(256, 256,
656 librbd::io::ReadResult{read_result},
657 0));
658 if (snap_name == NULL) {
659 ASSERT_TRUE(bl.contents_equal(read_bl));
660 } else {
661 ASSERT_TRUE(read_bl.is_zero());
662 }
663
9f95a23c
TL
664 // verify sparseness was preserved
665 {
666 librados::IoCtx io_ctx;
667 io_ctx.dup(m_ioctx);
668 librados::Rados rados(io_ctx);
669 EXPECT_EQ(0, rados.conf_set("rbd_cache", "false"));
670 EXPECT_EQ(0, rados.conf_set("rbd_sparse_read_threshold_bytes", "256"));
671 auto ictx3 = new librbd::ImageCtx(clone_name, "", snap_name, io_ctx,
672 true);
673 ASSERT_EQ(0, ictx3->state->open(0));
674 BOOST_SCOPE_EXIT(ictx3) {
675 ictx3->state->close();
676 } BOOST_SCOPE_EXIT_END;
677 std::map<uint64_t, uint64_t> expected_m;
678 bufferlist expected_bl;
679 if (ictx3->enable_sparse_copyup && sparse_read_supported) {
680 if (snap_name == NULL) {
681 expected_m = {{0, 512}, {1024, 256}};
682 expected_bl.append(std::string(256 * 3, '1'));
683 } else {
684 expected_m = {{0, 256}, {1024, 256}};
685 expected_bl.append(std::string(256 * 2, '1'));
686 }
687 } else {
688 expected_m = {{0, 1024 + 256}};
689 if (snap_name == NULL) {
690 expected_bl.append(std::string(256 * 2, '1'));
691 expected_bl.append(std::string(256 * 2, '\0'));
692 expected_bl.append(std::string(256 * 1, '1'));
693 } else {
694 expected_bl.append(std::string(256 * 1, '1'));
695 expected_bl.append(std::string(256 * 3, '\0'));
696 expected_bl.append(std::string(256 * 1, '1'));
697 }
698 }
699 std::map<uint64_t, uint64_t> read_m;
700 librbd::io::ReadResult sparse_read_result{&read_m, &read_bl};
701 EXPECT_EQ(1024 + 256,
702 ictx3->io_work_queue->read(0, 1024 + 256,
703 librbd::io::ReadResult{sparse_read_result},
704 0));
705 EXPECT_EQ(expected_m, read_m);
706 EXPECT_TRUE(expected_bl.contents_equal(read_bl));
707 }
708
7c673cae
FG
709 // verify the object map was properly updated
710 if ((ictx2->features & RBD_FEATURE_OBJECT_MAP) != 0) {
711 uint8_t state = OBJECT_EXISTS;
712 if ((ictx2->features & RBD_FEATURE_FAST_DIFF) != 0 &&
713 it != snaps.begin() && snap_name != NULL) {
714 state = OBJECT_EXISTS_CLEAN;
715 }
716
9f95a23c 717 librbd::ObjectMap<> *object_map = new librbd::ObjectMap<>(*ictx2, ictx2->snap_id);
7c673cae 718 C_SaferCond ctx;
9f95a23c 719 object_map->open(&ctx);
7c673cae
FG
720 ASSERT_EQ(0, ctx.wait());
721
9f95a23c
TL
722 std::shared_lock image_locker{ictx2->image_lock};
723 ASSERT_EQ(state, (*object_map)[0]);
724 object_map->put();
494da23a
TL
725 }
726 }
727}
728
729TEST_F(TestInternal, SnapshotCopyupZeros)
730{
731 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
732
733 librbd::ImageCtx *ictx;
734 ASSERT_EQ(0, open_image(m_image_name, &ictx));
735
736 // create an empty clone
737 ASSERT_EQ(0, snap_create(*ictx, "snap1"));
738 ASSERT_EQ(0,
739 ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
740 "snap1"));
741
742 uint64_t features;
743 ASSERT_EQ(0, librbd::get_features(ictx, &features));
744
745 std::string clone_name = get_temp_image_name();
746 int order = ictx->order;
747 ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap1", m_ioctx,
748 clone_name.c_str(), features, &order, 0, 0));
749
750 librbd::ImageCtx *ictx2;
751 ASSERT_EQ(0, open_image(clone_name, &ictx2));
752
753 ASSERT_EQ(0, snap_create(*ictx2, "snap1"));
754
755 bufferlist bl;
756 bl.append(std::string(256, '1'));
757 ASSERT_EQ(256, ictx2->io_work_queue->write(256, bl.length(), bufferlist{bl},
758 0));
759
760 librados::IoCtx snap_ctx;
761 snap_ctx.dup(ictx2->data_ctx);
762 snap_ctx.snap_set_read(CEPH_SNAPDIR);
763
764 librados::snap_set_t snap_set;
765 ASSERT_EQ(0, snap_ctx.list_snaps(ictx2->get_object_name(0), &snap_set));
766
767 // verify that snapshot wasn't affected
768 ASSERT_EQ(1U, snap_set.clones.size());
769 ASSERT_EQ(CEPH_NOSNAP, snap_set.clones[0].cloneid);
770
771 bufferptr read_ptr(256);
772 bufferlist read_bl;
773 read_bl.push_back(read_ptr);
774
775 std::list<std::string> snaps = {"snap1", ""};
776 librbd::io::ReadResult read_result{&read_bl};
777 for (std::list<std::string>::iterator it = snaps.begin();
778 it != snaps.end(); ++it) {
779 const char *snap_name = it->empty() ? NULL : it->c_str();
780 ASSERT_EQ(0, librbd::api::Image<>::snap_set(
781 ictx2, cls::rbd::UserSnapshotNamespace(), snap_name));
782
783 ASSERT_EQ(256,
784 ictx2->io_work_queue->read(0, 256,
785 librbd::io::ReadResult{read_result},
786 0));
787 ASSERT_TRUE(read_bl.is_zero());
788
789 ASSERT_EQ(256,
790 ictx2->io_work_queue->read(256, 256,
791 librbd::io::ReadResult{read_result},
792 0));
793 if (snap_name == NULL) {
794 ASSERT_TRUE(bl.contents_equal(read_bl));
795 } else {
796 ASSERT_TRUE(read_bl.is_zero());
797 }
798
799 // verify that only HEAD object map was updated
800 if ((ictx2->features & RBD_FEATURE_OBJECT_MAP) != 0) {
801 uint8_t state = OBJECT_EXISTS;
802 if (snap_name != NULL) {
803 state = OBJECT_NONEXISTENT;
804 }
805
9f95a23c 806 librbd::ObjectMap<> *object_map = new librbd::ObjectMap<>(*ictx2, ictx2->snap_id);
494da23a 807 C_SaferCond ctx;
9f95a23c 808 object_map->open(&ctx);
494da23a
TL
809 ASSERT_EQ(0, ctx.wait());
810
9f95a23c
TL
811 std::shared_lock image_locker{ictx2->image_lock};
812 ASSERT_EQ(state, (*object_map)[0]);
813 object_map->put();
494da23a
TL
814 }
815 }
816}
817
818TEST_F(TestInternal, SnapshotCopyupZerosMigration)
819{
820 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
821
822 librbd::ImageCtx *ictx;
823 ASSERT_EQ(0, open_image(m_image_name, &ictx));
824
825 uint64_t features;
826 ASSERT_EQ(0, librbd::get_features(ictx, &features));
827
828 close_image(ictx);
829
830 // migrate an empty image
831 std::string dst_name = get_temp_image_name();
832 librbd::ImageOptions dst_opts;
833 dst_opts.set(RBD_IMAGE_OPTION_FEATURES, features);
834 ASSERT_EQ(0, librbd::api::Migration<>::prepare(m_ioctx, m_image_name,
835 m_ioctx, dst_name,
836 dst_opts));
837
838 librbd::ImageCtx *ictx2;
839 ASSERT_EQ(0, open_image(dst_name, &ictx2));
840
841 ASSERT_EQ(0, snap_create(*ictx2, "snap1"));
842
843 bufferlist bl;
844 bl.append(std::string(256, '1'));
845 ASSERT_EQ(256, ictx2->io_work_queue->write(256, bl.length(), bufferlist{bl},
846 0));
847
848 librados::IoCtx snap_ctx;
849 snap_ctx.dup(ictx2->data_ctx);
850 snap_ctx.snap_set_read(CEPH_SNAPDIR);
851
852 librados::snap_set_t snap_set;
853 ASSERT_EQ(0, snap_ctx.list_snaps(ictx2->get_object_name(0), &snap_set));
854
855 // verify that snapshot wasn't affected
856 ASSERT_EQ(1U, snap_set.clones.size());
857 ASSERT_EQ(CEPH_NOSNAP, snap_set.clones[0].cloneid);
858
859 bufferptr read_ptr(256);
860 bufferlist read_bl;
861 read_bl.push_back(read_ptr);
862
863 std::list<std::string> snaps = {"snap1", ""};
864 librbd::io::ReadResult read_result{&read_bl};
865 for (std::list<std::string>::iterator it = snaps.begin();
866 it != snaps.end(); ++it) {
867 const char *snap_name = it->empty() ? NULL : it->c_str();
868 ASSERT_EQ(0, librbd::api::Image<>::snap_set(
869 ictx2, cls::rbd::UserSnapshotNamespace(), snap_name));
870
871 ASSERT_EQ(256,
872 ictx2->io_work_queue->read(0, 256,
873 librbd::io::ReadResult{read_result},
874 0));
875 ASSERT_TRUE(read_bl.is_zero());
876
877 ASSERT_EQ(256,
878 ictx2->io_work_queue->read(256, 256,
879 librbd::io::ReadResult{read_result},
880 0));
881 if (snap_name == NULL) {
882 ASSERT_TRUE(bl.contents_equal(read_bl));
883 } else {
884 ASSERT_TRUE(read_bl.is_zero());
885 }
886
887 // verify that only HEAD object map was updated
888 if ((ictx2->features & RBD_FEATURE_OBJECT_MAP) != 0) {
889 uint8_t state = OBJECT_EXISTS;
890 if (snap_name != NULL) {
891 state = OBJECT_NONEXISTENT;
892 }
893
9f95a23c 894 librbd::ObjectMap<> *object_map = new librbd::ObjectMap<>(*ictx2, ictx2->snap_id);
494da23a 895 C_SaferCond ctx;
9f95a23c 896 object_map->open(&ctx);
494da23a
TL
897 ASSERT_EQ(0, ctx.wait());
898
9f95a23c
TL
899 std::shared_lock image_locker{ictx2->image_lock};
900 ASSERT_EQ(state, (*object_map)[0]);
901 object_map->put();
7c673cae
FG
902 }
903 }
904}
905
906TEST_F(TestInternal, ResizeCopyup)
907{
908 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
909
910 m_image_name = get_temp_image_name();
911 m_image_size = 1 << 14;
912
913 uint64_t features = 0;
914 get_features(&features);
915 int order = 12;
916 ASSERT_EQ(0, m_rbd.create2(m_ioctx, m_image_name.c_str(), m_image_size,
917 features, &order));
918
919 librbd::ImageCtx *ictx;
920 ASSERT_EQ(0, open_image(m_image_name, &ictx));
921
922 bufferlist bl;
923 bl.append(std::string(4096, '1'));
924 for (size_t i = 0; i < m_image_size; i += bl.length()) {
925 ASSERT_EQ((ssize_t)bl.length(),
926 ictx->io_work_queue->write(i, bl.length(),
927 bufferlist{bl}, 0));
928 }
929
930 ASSERT_EQ(0, snap_create(*ictx, "snap1"));
931 ASSERT_EQ(0,
932 ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
933 "snap1"));
934
935 std::string clone_name = get_temp_image_name();
936 ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap1", m_ioctx,
937 clone_name.c_str(), features, &order, 0, 0));
938
939 librbd::ImageCtx *ictx2;
940 ASSERT_EQ(0, open_image(clone_name, &ictx2));
941 ASSERT_EQ(0, snap_create(*ictx2, "snap1"));
942
943 bufferptr read_ptr(bl.length());
944 bufferlist read_bl;
945 read_bl.push_back(read_ptr);
946
947 // verify full / partial object removal properly copyup
948 librbd::NoOpProgressContext no_op;
949 ASSERT_EQ(0, ictx2->operations->resize(m_image_size - (1 << order) - 32,
950 true, no_op));
951 ASSERT_EQ(0, ictx2->operations->resize(m_image_size - (2 << order) - 32,
952 true, no_op));
11fdf7f2
TL
953 ASSERT_EQ(0, librbd::api::Image<>::snap_set(ictx2,
954 cls::rbd::UserSnapshotNamespace(),
955 "snap1"));
7c673cae
FG
956
957 {
958 // hide the parent from the snapshot
9f95a23c 959 std::unique_lock image_locker{ictx2->image_lock};
11fdf7f2 960 ictx2->snap_info.begin()->second.parent = librbd::ParentImageInfo();
7c673cae
FG
961 }
962
963 librbd::io::ReadResult read_result{&read_bl};
964 for (size_t i = 2 << order; i < m_image_size; i += bl.length()) {
965 ASSERT_EQ((ssize_t)bl.length(),
966 ictx2->io_work_queue->read(i, bl.length(),
967 librbd::io::ReadResult{read_result},
968 0));
969 ASSERT_TRUE(bl.contents_equal(read_bl));
970 }
971}
972
973TEST_F(TestInternal, DiscardCopyup)
974{
975 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
976
977 CephContext* cct = reinterpret_cast<CephContext*>(_rados.cct());
11fdf7f2 978 REQUIRE(!cct->_conf.get_val<bool>("rbd_skip_partial_discard"));
7c673cae
FG
979
980 m_image_name = get_temp_image_name();
981 m_image_size = 1 << 14;
982
983 uint64_t features = 0;
984 get_features(&features);
985 int order = 12;
986 ASSERT_EQ(0, m_rbd.create2(m_ioctx, m_image_name.c_str(), m_image_size,
987 features, &order));
988
989 librbd::ImageCtx *ictx;
990 ASSERT_EQ(0, open_image(m_image_name, &ictx));
991
992 bufferlist bl;
993 bl.append(std::string(4096, '1'));
994 for (size_t i = 0; i < m_image_size; i += bl.length()) {
995 ASSERT_EQ((ssize_t)bl.length(),
996 ictx->io_work_queue->write(i, bl.length(),
997 bufferlist{bl}, 0));
998 }
999
1000 ASSERT_EQ(0, snap_create(*ictx, "snap1"));
1001 ASSERT_EQ(0,
1002 ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
1003 "snap1"));
1004
1005 std::string clone_name = get_temp_image_name();
1006 ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap1", m_ioctx,
1007 clone_name.c_str(), features, &order, 0, 0));
1008
1009 librbd::ImageCtx *ictx2;
1010 ASSERT_EQ(0, open_image(clone_name, &ictx2));
1011
1012 ASSERT_EQ(0, snap_create(*ictx2, "snap1"));
1013
1014 bufferptr read_ptr(bl.length());
1015 bufferlist read_bl;
1016 read_bl.push_back(read_ptr);
1017
1018 ASSERT_EQ(static_cast<int>(m_image_size - 64),
1019 ictx2->io_work_queue->discard(32, m_image_size - 64, false));
11fdf7f2
TL
1020 ASSERT_EQ(0, librbd::api::Image<>::snap_set(ictx2,
1021 cls::rbd::UserSnapshotNamespace(),
1022 "snap1"));
7c673cae
FG
1023
1024 {
1025 // hide the parent from the snapshot
9f95a23c 1026 std::unique_lock image_locker{ictx2->image_lock};
11fdf7f2 1027 ictx2->snap_info.begin()->second.parent = librbd::ParentImageInfo();
7c673cae
FG
1028 }
1029
1030 librbd::io::ReadResult read_result{&read_bl};
1031 for (size_t i = 0; i < m_image_size; i += bl.length()) {
1032 ASSERT_EQ((ssize_t)bl.length(),
1033 ictx2->io_work_queue->read(i, bl.length(),
1034 librbd::io::ReadResult{read_result},
1035 0));
1036 ASSERT_TRUE(bl.contents_equal(read_bl));
1037 }
1038}
1039
1040TEST_F(TestInternal, ShrinkFlushesCache) {
1041 librbd::ImageCtx *ictx;
1042 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1043
1044 std::string buffer(4096, '1');
1045
1046 // ensure write-path is initialized
1047 bufferlist write_bl;
1048 write_bl.append(buffer);
1049 ictx->io_work_queue->write(0, buffer.size(), bufferlist{write_bl}, 0);
1050
1051 C_SaferCond cond_ctx;
1052 auto c = librbd::io::AioCompletion::create(&cond_ctx);
1053 c->get();
1054 ictx->io_work_queue->aio_write(c, 0, buffer.size(), bufferlist{write_bl}, 0);
1055
1056 librbd::NoOpProgressContext no_op;
1057 ASSERT_EQ(0, ictx->operations->resize(m_image_size >> 1, true, no_op));
1058
1059 ASSERT_TRUE(c->is_complete());
1060 ASSERT_EQ(0, c->wait_for_complete());
1061 ASSERT_EQ(0, cond_ctx.wait());
1062 c->put();
1063}
1064
1065TEST_F(TestInternal, ImageOptions) {
1066 rbd_image_options_t opts1 = NULL, opts2 = NULL;
1067 uint64_t uint64_val1 = 10, uint64_val2 = 0;
1068 std::string string_val1;
1069
1070 librbd::image_options_create(&opts1);
1071 ASSERT_NE((rbd_image_options_t)NULL, opts1);
1072 ASSERT_TRUE(librbd::image_options_is_empty(opts1));
1073
1074 ASSERT_EQ(-EINVAL, librbd::image_options_get(opts1, RBD_IMAGE_OPTION_FEATURES,
1075 &string_val1));
1076 ASSERT_EQ(-ENOENT, librbd::image_options_get(opts1, RBD_IMAGE_OPTION_FEATURES,
1077 &uint64_val1));
1078
1079 ASSERT_EQ(-EINVAL, librbd::image_options_set(opts1, RBD_IMAGE_OPTION_FEATURES,
1080 string_val1));
1081
1082 ASSERT_EQ(0, librbd::image_options_set(opts1, RBD_IMAGE_OPTION_FEATURES,
1083 uint64_val1));
1084 ASSERT_FALSE(librbd::image_options_is_empty(opts1));
1085 ASSERT_EQ(0, librbd::image_options_get(opts1, RBD_IMAGE_OPTION_FEATURES,
1086 &uint64_val2));
1087 ASSERT_EQ(uint64_val1, uint64_val2);
1088
1089 librbd::image_options_create_ref(&opts2, opts1);
1090 ASSERT_NE((rbd_image_options_t)NULL, opts2);
1091 ASSERT_FALSE(librbd::image_options_is_empty(opts2));
1092
1093 uint64_val2 = 0;
1094 ASSERT_NE(uint64_val1, uint64_val2);
1095 ASSERT_EQ(0, librbd::image_options_get(opts2, RBD_IMAGE_OPTION_FEATURES,
1096 &uint64_val2));
1097 ASSERT_EQ(uint64_val1, uint64_val2);
1098
1099 uint64_val2++;
1100 ASSERT_NE(uint64_val1, uint64_val2);
1101 ASSERT_EQ(-ENOENT, librbd::image_options_get(opts1, RBD_IMAGE_OPTION_ORDER,
1102 &uint64_val1));
1103 ASSERT_EQ(-ENOENT, librbd::image_options_get(opts2, RBD_IMAGE_OPTION_ORDER,
1104 &uint64_val2));
1105 ASSERT_EQ(0, librbd::image_options_set(opts2, RBD_IMAGE_OPTION_ORDER,
1106 uint64_val2));
1107 ASSERT_EQ(0, librbd::image_options_get(opts1, RBD_IMAGE_OPTION_ORDER,
1108 &uint64_val1));
1109 ASSERT_EQ(0, librbd::image_options_get(opts2, RBD_IMAGE_OPTION_ORDER,
1110 &uint64_val2));
1111 ASSERT_EQ(uint64_val1, uint64_val2);
1112
1113 librbd::image_options_destroy(opts1);
1114
1115 uint64_val2++;
1116 ASSERT_NE(uint64_val1, uint64_val2);
1117 ASSERT_EQ(0, librbd::image_options_get(opts2, RBD_IMAGE_OPTION_ORDER,
1118 &uint64_val2));
1119 ASSERT_EQ(uint64_val1, uint64_val2);
1120
1121 ASSERT_EQ(0, librbd::image_options_unset(opts2, RBD_IMAGE_OPTION_ORDER));
1122 ASSERT_EQ(-ENOENT, librbd::image_options_unset(opts2, RBD_IMAGE_OPTION_ORDER));
1123
1124 librbd::image_options_clear(opts2);
1125 ASSERT_EQ(-ENOENT, librbd::image_options_get(opts2, RBD_IMAGE_OPTION_FEATURES,
1126 &uint64_val2));
1127 ASSERT_TRUE(librbd::image_options_is_empty(opts2));
1128
1129 librbd::image_options_destroy(opts2);
1130}
1131
1132TEST_F(TestInternal, WriteFullCopyup) {
1133 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1134
1135 librbd::ImageCtx *ictx;
1136 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1137
1138 librbd::NoOpProgressContext no_op;
1139 ASSERT_EQ(0, ictx->operations->resize(1 << ictx->order, true, no_op));
1140
1141 bufferlist bl;
1142 bl.append(std::string(1 << ictx->order, '1'));
1143 ASSERT_EQ((ssize_t)bl.length(),
1144 ictx->io_work_queue->write(0, bl.length(), bufferlist{bl}, 0));
11fdf7f2 1145 ASSERT_EQ(0, ictx->io_work_queue->flush());
7c673cae
FG
1146
1147 ASSERT_EQ(0, create_snapshot("snap1", true));
1148
1149 std::string clone_name = get_temp_image_name();
1150 int order = ictx->order;
1151 ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap1", m_ioctx,
1152 clone_name.c_str(), ictx->features, &order, 0, 0));
1153
1154 TestInternal *parent = this;
1155 librbd::ImageCtx *ictx2 = NULL;
1156 BOOST_SCOPE_EXIT( (&m_ioctx) (clone_name) (parent) (&ictx2) ) {
1157 if (ictx2 != NULL) {
1158 ictx2->operations->snap_remove(cls::rbd::UserSnapshotNamespace(),
1159 "snap1");
1160 parent->close_image(ictx2);
1161 }
1162
1163 librbd::NoOpProgressContext remove_no_op;
11fdf7f2
TL
1164 ASSERT_EQ(0, librbd::api::Image<>::remove(m_ioctx, clone_name,
1165 remove_no_op));
7c673cae
FG
1166 } BOOST_SCOPE_EXIT_END;
1167
1168 ASSERT_EQ(0, open_image(clone_name, &ictx2));
1169 ASSERT_EQ(0, ictx2->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
1170 "snap1"));
1171
1172 bufferlist write_full_bl;
1173 write_full_bl.append(std::string(1 << ictx2->order, '2'));
1174 ASSERT_EQ((ssize_t)write_full_bl.length(),
1175 ictx2->io_work_queue->write(0, write_full_bl.length(),
1176 bufferlist{write_full_bl}, 0));
1177
1178 ASSERT_EQ(0, ictx2->operations->flatten(no_op));
1179
1180 bufferptr read_ptr(bl.length());
1181 bufferlist read_bl;
1182 read_bl.push_back(read_ptr);
1183
1184 librbd::io::ReadResult read_result{&read_bl};
1185 ASSERT_EQ((ssize_t)read_bl.length(),
1186 ictx2->io_work_queue->read(0, read_bl.length(),
1187 librbd::io::ReadResult{read_result}, 0));
1188 ASSERT_TRUE(write_full_bl.contents_equal(read_bl));
1189
11fdf7f2
TL
1190 ASSERT_EQ(0, librbd::api::Image<>::snap_set(ictx2,
1191 cls::rbd::UserSnapshotNamespace(),
1192 "snap1"));
7c673cae
FG
1193 ASSERT_EQ((ssize_t)read_bl.length(),
1194 ictx2->io_work_queue->read(0, read_bl.length(),
1195 librbd::io::ReadResult{read_result}, 0));
1196 ASSERT_TRUE(bl.contents_equal(read_bl));
1197}
1198
7c673cae
FG
1199static int iterate_cb(uint64_t off, size_t len, int exists, void *arg)
1200{
1201 interval_set<uint64_t> *diff = static_cast<interval_set<uint64_t> *>(arg);
1202 diff->insert(off, len);
1203 return 0;
1204}
1205
1206TEST_F(TestInternal, DiffIterateCloneOverwrite) {
1207 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1208
1209 librbd::RBD rbd;
1210 librbd::Image image;
1211 uint64_t size = 20 << 20;
1212 int order = 0;
1213
1214 ASSERT_EQ(0, rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
1215
1216 bufferlist bl;
1217 bl.append(std::string(4096, '1'));
1218 ASSERT_EQ(4096, image.write(0, 4096, bl));
1219
1220 interval_set<uint64_t> one;
1221 ASSERT_EQ(0, image.diff_iterate2(NULL, 0, size, false, false, iterate_cb,
1222 (void *)&one));
1223 ASSERT_EQ(0, image.snap_create("one"));
1224 ASSERT_EQ(0, image.snap_protect("one"));
1225
1226 std::string clone_name = this->get_temp_image_name();
1227 ASSERT_EQ(0, rbd.clone(m_ioctx, m_image_name.c_str(), "one", m_ioctx,
1228 clone_name.c_str(), RBD_FEATURE_LAYERING, &order));
1229
1230 librbd::ImageCtx *ictx;
1231 ASSERT_EQ(0, open_image(clone_name, &ictx));
1232 ASSERT_EQ(0, snap_create(*ictx, "one"));
1233 ASSERT_EQ(0,
1234 ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
1235 "one"));
1236
1237 // Simulate a client that doesn't support deep flatten (old librbd / krbd)
1238 // which will copy up the full object from the parent
1239 std::string oid = ictx->object_prefix + ".0000000000000000";
1240 librados::IoCtx io_ctx;
1241 io_ctx.dup(m_ioctx);
1242 io_ctx.selfmanaged_snap_set_write_ctx(ictx->snapc.seq, ictx->snaps);
1243 ASSERT_EQ(0, io_ctx.write(oid, bl, 4096, 4096));
1244
1245 interval_set<uint64_t> diff;
11fdf7f2
TL
1246 ASSERT_EQ(0, librbd::api::Image<>::snap_set(ictx,
1247 cls::rbd::UserSnapshotNamespace(),
1248 "one"));
7c673cae
FG
1249 ASSERT_EQ(0, librbd::api::DiffIterate<>::diff_iterate(
1250 ictx, cls::rbd::UserSnapshotNamespace(), nullptr, 0, size, true, false,
1251 iterate_cb, (void *)&diff));
1252 ASSERT_EQ(one, diff);
1253}
1254
1255TEST_F(TestInternal, TestCoR)
1256{
1257 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1258
1259 std::string config_value;
1260 ASSERT_EQ(0, _rados.conf_get("rbd_clone_copy_on_read", config_value));
1261 if (config_value == "false") {
1262 std::cout << "SKIPPING due to disabled rbd_copy_on_read" << std::endl;
1263 return;
1264 }
1265
1266 m_image_name = get_temp_image_name();
1267 m_image_size = 4 << 20;
1268
1269 int order = 12; // smallest object size is 4K
1270 uint64_t features;
1271 ASSERT_TRUE(get_features(&features));
1272
1273 ASSERT_EQ(0, create_image_full_pp(m_rbd, m_ioctx, m_image_name, m_image_size,
1274 features, false, &order));
1275
1276 librbd::Image image;
1277 ASSERT_EQ(0, m_rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
1278
1279 librbd::image_info_t info;
1280 ASSERT_EQ(0, image.stat(info, sizeof(info)));
1281
1282 const int object_num = info.size / info.obj_size;
1283 printf("made parent image \"%s\": %ldK (%d * %" PRIu64 "K)\n", m_image_name.c_str(),
1284 (unsigned long)m_image_size, object_num, info.obj_size/1024);
1285
1286 // write something into parent
1287 char test_data[TEST_IO_SIZE + 1];
1288 for (int i = 0; i < TEST_IO_SIZE; ++i) {
1289 test_data[i] = (char) (rand() % (126 - 33) + 33);
1290 }
1291 test_data[TEST_IO_SIZE] = '\0';
1292
1293 // generate a random map which covers every objects with random
1294 // offset
1295 map<uint64_t, uint64_t> write_tracker;
1296 generate_random_iomap(image, object_num, info.obj_size, 100, write_tracker);
1297
1298 printf("generated random write map:\n");
1299 for (map<uint64_t, uint64_t>::iterator itr = write_tracker.begin();
1300 itr != write_tracker.end(); ++itr)
11fdf7f2 1301 printf("\t [%-8lu, %-8lu]\n",
7c673cae
FG
1302 (unsigned long)itr->first, (unsigned long)itr->second);
1303
1304 bufferlist bl;
1305 bl.append(test_data, TEST_IO_SIZE);
1306
1307 printf("write data based on random map\n");
1308 for (map<uint64_t, uint64_t>::iterator itr = write_tracker.begin();
1309 itr != write_tracker.end(); ++itr) {
11fdf7f2 1310 printf("\twrite object-%-4lu\t\n", (unsigned long)itr->first);
7c673cae
FG
1311 ASSERT_EQ(TEST_IO_SIZE, image.write(itr->second, TEST_IO_SIZE, bl));
1312 }
1313
d2e6a577
FG
1314 ASSERT_EQ(0, image.flush());
1315
7c673cae
FG
1316 bufferlist readbl;
1317 printf("verify written data by reading\n");
1318 {
1319 map<uint64_t, uint64_t>::iterator itr = write_tracker.begin();
11fdf7f2 1320 printf("\tread object-%-4lu\n", (unsigned long)itr->first);
7c673cae
FG
1321 ASSERT_EQ(TEST_IO_SIZE, image.read(itr->second, TEST_IO_SIZE, readbl));
1322 ASSERT_TRUE(readbl.contents_equal(bl));
1323 }
1324
1325 int64_t data_pool_id = image.get_data_pool_id();
1326 rados_ioctx_t d_ioctx;
d2e6a577
FG
1327 ASSERT_EQ(0, rados_wait_for_latest_osdmap(_cluster));
1328 ASSERT_EQ(0, rados_ioctx_create2(_cluster, data_pool_id, &d_ioctx));
1329
1330 std::string block_name_prefix = image.get_block_name_prefix() + ".";
7c673cae
FG
1331
1332 const char *entry;
1333 rados_list_ctx_t list_ctx;
1334 set<string> obj_checker;
1335 ASSERT_EQ(0, rados_nobjects_list_open(d_ioctx, &list_ctx));
1336 while (rados_nobjects_list_next(list_ctx, &entry, NULL, NULL) != -ENOENT) {
d2e6a577
FG
1337 if (boost::starts_with(entry, block_name_prefix)) {
1338 const char *block_name_suffix = entry + block_name_prefix.length();
7c673cae
FG
1339 obj_checker.insert(block_name_suffix);
1340 }
1341 }
1342 rados_nobjects_list_close(list_ctx);
1343
1344 std::string snapname = "snap";
1345 std::string clonename = get_temp_image_name();
1346 ASSERT_EQ(0, image.snap_create(snapname.c_str()));
1347 ASSERT_EQ(0, image.close());
1348 ASSERT_EQ(0, m_rbd.open(m_ioctx, image, m_image_name.c_str(), snapname.c_str()));
1349 ASSERT_EQ(0, image.snap_protect(snapname.c_str()));
1350 printf("made snapshot \"%s@parent_snap\" and protect it\n", m_image_name.c_str());
1351
1352 ASSERT_EQ(0, clone_image_pp(m_rbd, image, m_ioctx, m_image_name.c_str(), snapname.c_str(),
1353 m_ioctx, clonename.c_str(), features));
1354 ASSERT_EQ(0, image.close());
1355 ASSERT_EQ(0, m_rbd.open(m_ioctx, image, clonename.c_str(), NULL));
1356 printf("made and opened clone \"%s\"\n", clonename.c_str());
1357
1358 printf("read from \"child\"\n");
1359 {
1360 map<uint64_t, uint64_t>::iterator itr = write_tracker.begin();
11fdf7f2 1361 printf("\tread object-%-4lu\n", (unsigned long)itr->first);
7c673cae
FG
1362 ASSERT_EQ(TEST_IO_SIZE, image.read(itr->second, TEST_IO_SIZE, readbl));
1363 ASSERT_TRUE(readbl.contents_equal(bl));
1364 }
1365
1366 for (map<uint64_t, uint64_t>::iterator itr = write_tracker.begin();
1367 itr != write_tracker.end(); ++itr) {
11fdf7f2 1368 printf("\tread object-%-4lu\n", (unsigned long)itr->first);
7c673cae
FG
1369 ASSERT_EQ(TEST_IO_SIZE, image.read(itr->second, TEST_IO_SIZE, readbl));
1370 ASSERT_TRUE(readbl.contents_equal(bl));
1371 }
1372
1373 printf("read again reversely\n");
1374 for (map<uint64_t, uint64_t>::iterator itr = --write_tracker.end();
1375 itr != write_tracker.begin(); --itr) {
11fdf7f2 1376 printf("\tread object-%-4lu\n", (unsigned long)itr->first);
7c673cae
FG
1377 ASSERT_EQ(TEST_IO_SIZE, image.read(itr->second, TEST_IO_SIZE, readbl));
1378 ASSERT_TRUE(readbl.contents_equal(bl));
1379 }
1380
1381 // close child to flush all copy-on-read
1382 ASSERT_EQ(0, image.close());
1383
1384 printf("check whether child image has the same set of objects as parent\n");
1385 ASSERT_EQ(0, m_rbd.open(m_ioctx, image, clonename.c_str(), NULL));
d2e6a577 1386 block_name_prefix = image.get_block_name_prefix() + ".";
7c673cae
FG
1387
1388 ASSERT_EQ(0, rados_nobjects_list_open(d_ioctx, &list_ctx));
1389 while (rados_nobjects_list_next(list_ctx, &entry, NULL, NULL) != -ENOENT) {
d2e6a577
FG
1390 if (boost::starts_with(entry, block_name_prefix)) {
1391 const char *block_name_suffix = entry + block_name_prefix.length();
7c673cae
FG
1392 set<string>::iterator it = obj_checker.find(block_name_suffix);
1393 ASSERT_TRUE(it != obj_checker.end());
1394 obj_checker.erase(it);
1395 }
1396 }
1397 rados_nobjects_list_close(list_ctx);
1398 ASSERT_TRUE(obj_checker.empty());
1399 ASSERT_EQ(0, image.close());
1400
1401 rados_ioctx_destroy(d_ioctx);
1402}
1403
1404TEST_F(TestInternal, FlattenNoEmptyObjects)
1405{
1406 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1407
1408 m_image_name = get_temp_image_name();
1409 m_image_size = 4 << 20;
1410
1411 int order = 12; // smallest object size is 4K
1412 uint64_t features;
1413 ASSERT_TRUE(get_features(&features));
1414
1415 ASSERT_EQ(0, create_image_full_pp(m_rbd, m_ioctx, m_image_name, m_image_size,
1416 features, false, &order));
1417
1418 librbd::Image image;
1419 ASSERT_EQ(0, m_rbd.open(m_ioctx, image, m_image_name.c_str(), NULL));
1420
1421 librbd::image_info_t info;
1422 ASSERT_EQ(0, image.stat(info, sizeof(info)));
1423
1424 const int object_num = info.size / info.obj_size;
1425 printf("made parent image \"%s\": %" PRIu64 "K (%d * %" PRIu64 "K)\n",
1426 m_image_name.c_str(), m_image_size, object_num, info.obj_size/1024);
1427
1428 // write something into parent
1429 char test_data[TEST_IO_SIZE + 1];
1430 for (int i = 0; i < TEST_IO_SIZE; ++i) {
1431 test_data[i] = (char) (rand() % (126 - 33) + 33);
1432 }
1433 test_data[TEST_IO_SIZE] = '\0';
1434
1435 // generate a random map which covers every objects with random
1436 // offset
1437 map<uint64_t, uint64_t> write_tracker;
1438 generate_random_iomap(image, object_num, info.obj_size, 100, write_tracker);
1439
1440 printf("generated random write map:\n");
1441 for (map<uint64_t, uint64_t>::iterator itr = write_tracker.begin();
1442 itr != write_tracker.end(); ++itr)
11fdf7f2 1443 printf("\t [%-8lu, %-8lu]\n",
7c673cae
FG
1444 (unsigned long)itr->first, (unsigned long)itr->second);
1445
1446 bufferlist bl;
1447 bl.append(test_data, TEST_IO_SIZE);
1448
1449 printf("write data based on random map\n");
1450 for (map<uint64_t, uint64_t>::iterator itr = write_tracker.begin();
1451 itr != write_tracker.end(); ++itr) {
11fdf7f2 1452 printf("\twrite object-%-4lu\t\n", (unsigned long)itr->first);
7c673cae
FG
1453 ASSERT_EQ(TEST_IO_SIZE, image.write(itr->second, TEST_IO_SIZE, bl));
1454 }
1455
d2e6a577
FG
1456 ASSERT_EQ(0, image.flush());
1457
7c673cae
FG
1458 bufferlist readbl;
1459 printf("verify written data by reading\n");
1460 {
1461 map<uint64_t, uint64_t>::iterator itr = write_tracker.begin();
11fdf7f2 1462 printf("\tread object-%-4lu\n", (unsigned long)itr->first);
7c673cae
FG
1463 ASSERT_EQ(TEST_IO_SIZE, image.read(itr->second, TEST_IO_SIZE, readbl));
1464 ASSERT_TRUE(readbl.contents_equal(bl));
1465 }
1466
1467 int64_t data_pool_id = image.get_data_pool_id();
1468 rados_ioctx_t d_ioctx;
d2e6a577
FG
1469 ASSERT_EQ(0, rados_wait_for_latest_osdmap(_cluster));
1470 ASSERT_EQ(0, rados_ioctx_create2(_cluster, data_pool_id, &d_ioctx));
1471
1472 std::string block_name_prefix = image.get_block_name_prefix() + ".";
7c673cae
FG
1473
1474 const char *entry;
1475 rados_list_ctx_t list_ctx;
1476 set<string> obj_checker;
1477 ASSERT_EQ(0, rados_nobjects_list_open(d_ioctx, &list_ctx));
1478 while (rados_nobjects_list_next(list_ctx, &entry, NULL, NULL) != -ENOENT) {
d2e6a577
FG
1479 if (boost::starts_with(entry, block_name_prefix)) {
1480 const char *block_name_suffix = entry + block_name_prefix.length();
7c673cae
FG
1481 obj_checker.insert(block_name_suffix);
1482 }
1483 }
1484 rados_nobjects_list_close(list_ctx);
1485
1486 std::string snapname = "snap";
1487 std::string clonename = get_temp_image_name();
1488 ASSERT_EQ(0, image.snap_create(snapname.c_str()));
1489 ASSERT_EQ(0, image.close());
1490 ASSERT_EQ(0, m_rbd.open(m_ioctx, image, m_image_name.c_str(), snapname.c_str()));
1491 ASSERT_EQ(0, image.snap_protect(snapname.c_str()));
1492 printf("made snapshot \"%s@parent_snap\" and protect it\n", m_image_name.c_str());
1493
1494 ASSERT_EQ(0, clone_image_pp(m_rbd, image, m_ioctx, m_image_name.c_str(), snapname.c_str(),
1495 m_ioctx, clonename.c_str(), features));
1496 ASSERT_EQ(0, image.close());
1497
1498 ASSERT_EQ(0, m_rbd.open(m_ioctx, image, clonename.c_str(), NULL));
1499 printf("made and opened clone \"%s\"\n", clonename.c_str());
1500
1501 printf("flattening clone: \"%s\"\n", clonename.c_str());
1502 ASSERT_EQ(0, image.flatten());
1503
1504 printf("check whether child image has the same set of objects as parent\n");
d2e6a577 1505 block_name_prefix = image.get_block_name_prefix() + ".";
7c673cae
FG
1506
1507 ASSERT_EQ(0, rados_nobjects_list_open(d_ioctx, &list_ctx));
1508 while (rados_nobjects_list_next(list_ctx, &entry, NULL, NULL) != -ENOENT) {
d2e6a577
FG
1509 if (boost::starts_with(entry, block_name_prefix)) {
1510 const char *block_name_suffix = entry + block_name_prefix.length();
7c673cae
FG
1511 set<string>::iterator it = obj_checker.find(block_name_suffix);
1512 ASSERT_TRUE(it != obj_checker.end());
1513 obj_checker.erase(it);
1514 }
1515 }
1516 rados_nobjects_list_close(list_ctx);
1517 ASSERT_TRUE(obj_checker.empty());
1518 ASSERT_EQ(0, image.close());
1519
1520 rados_ioctx_destroy(d_ioctx);
1521}
11fdf7f2
TL
1522
1523TEST_F(TestInternal, PoolMetadataConfApply) {
1524 REQUIRE_FORMAT_V2();
1525
1526 librbd::api::PoolMetadata<>::remove(m_ioctx, "conf_rbd_cache");
1527
1528 librbd::ImageCtx *ictx;
1529 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1530
1531 bool cache = ictx->cache;
1532 std::string rbd_conf_cache = cache ? "true" : "false";
1533 std::string new_rbd_conf_cache = !cache ? "true" : "false";
1534
1535 ASSERT_EQ(0, librbd::api::PoolMetadata<>::set(m_ioctx, "conf_rbd_cache",
1536 new_rbd_conf_cache));
1537 ASSERT_EQ(0, ictx->state->refresh());
1538 ASSERT_EQ(!cache, ictx->cache);
1539
1540 ASSERT_EQ(0, ictx->operations->metadata_set("conf_rbd_cache",
1541 rbd_conf_cache));
1542 ASSERT_EQ(cache, ictx->cache);
1543
1544 ASSERT_EQ(0, ictx->operations->metadata_remove("conf_rbd_cache"));
1545 ASSERT_EQ(!cache, ictx->cache);
1546
1547 ASSERT_EQ(0, librbd::api::PoolMetadata<>::remove(m_ioctx, "conf_rbd_cache"));
1548 ASSERT_EQ(0, ictx->state->refresh());
1549 ASSERT_EQ(cache, ictx->cache);
1550 close_image(ictx);
1551
1552 ASSERT_EQ(0, librbd::api::PoolMetadata<>::set(m_ioctx,
1553 "conf_rbd_default_order",
1554 "17"));
1555 ASSERT_EQ(0, librbd::api::PoolMetadata<>::set(m_ioctx,
1556 "conf_rbd_journal_order",
1557 "13"));
1558 std::string image_name = get_temp_image_name();
1559 int order = 0;
1560 uint64_t features;
1561 ASSERT_TRUE(get_features(&features));
1562 ASSERT_EQ(0, create_image_full_pp(m_rbd, m_ioctx, image_name, m_image_size,
1563 features, false, &order));
1564
1565 ASSERT_EQ(0, open_image(image_name, &ictx));
1566 ASSERT_EQ(ictx->order, 17);
1567 ASSERT_EQ(ictx->config.get_val<uint64_t>("rbd_journal_order"), 13U);
1568
1569 if (is_feature_enabled(RBD_FEATURE_JOURNALING)) {
1570 uint8_t order;
1571 uint8_t splay_width;
1572 int64_t pool_id;
1573 C_SaferCond cond;
1574 cls::journal::client::get_immutable_metadata(m_ioctx, "journal." + ictx->id,
1575 &order, &splay_width, &pool_id,
1576 &cond);
1577 ASSERT_EQ(0, cond.wait());
1578 ASSERT_EQ(order, 13);
1579 ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_JOURNALING,
1580 false));
1581 ASSERT_EQ(0, librbd::api::PoolMetadata<>::set(m_ioctx,
1582 "conf_rbd_journal_order",
1583 "14"));
1584 ASSERT_EQ(0, ictx->operations->update_features(RBD_FEATURE_JOURNALING,
1585 true));
1586 ASSERT_EQ(ictx->config.get_val<uint64_t>("rbd_journal_order"), 14U);
1587
1588 C_SaferCond cond1;
1589 cls::journal::client::get_immutable_metadata(m_ioctx, "journal." + ictx->id,
1590 &order, &splay_width, &pool_id,
1591 &cond1);
1592 ASSERT_EQ(0, cond1.wait());
1593 ASSERT_EQ(order, 14);
1594 }
1595
1596 ASSERT_EQ(0, librbd::api::PoolMetadata<>::remove(m_ioctx,
1597 "conf_rbd_default_order"));
1598 ASSERT_EQ(0, librbd::api::PoolMetadata<>::remove(m_ioctx,
1599 "conf_rbd_journal_order"));
1600}
1601
1602TEST_F(TestInternal, Sparsify) {
1603 librbd::ImageCtx *ictx;
1604 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1605
81eedcae
TL
1606 bool sparsify_supported = is_sparsify_supported(ictx->data_ctx,
1607 ictx->get_object_name(10));
11fdf7f2
TL
1608 bool sparse_read_supported = is_sparse_read_supported(
1609 ictx->data_ctx, ictx->get_object_name(10));
1610
81eedcae
TL
1611 std::cout << "sparsify_supported=" << sparsify_supported << std::endl;
1612 std::cout << "sparse_read_supported=" << sparse_read_supported << std::endl;
1613
11fdf7f2
TL
1614 librbd::NoOpProgressContext no_op;
1615 ASSERT_EQ(0, ictx->operations->resize((1 << ictx->order) * 20, true, no_op));
1616
1617 bufferlist bl;
1618 bl.append(std::string(4096, '\0'));
1619
1620 ASSERT_EQ((ssize_t)bl.length(),
1621 ictx->io_work_queue->write(0, bl.length(), bufferlist{bl}, 0));
1622
81eedcae
TL
1623 ASSERT_EQ((ssize_t)bl.length(),
1624 ictx->io_work_queue->write((1 << ictx->order) * 1 + 512,
1625 bl.length(), bufferlist{bl}, 0));
1626
11fdf7f2
TL
1627 bl.append(std::string(4096, '1'));
1628 bl.append(std::string(4096, '\0'));
1629 bl.append(std::string(4096, '2'));
81eedcae 1630 bl.append(std::string(4096 - 1, '\0'));
11fdf7f2
TL
1631 ASSERT_EQ((ssize_t)bl.length(),
1632 ictx->io_work_queue->write((1 << ictx->order) * 10, bl.length(),
1633 bufferlist{bl}, 0));
81eedcae
TL
1634
1635 bufferlist bl2;
1636 bl2.append(std::string(4096 - 1, '\0'));
1637 ASSERT_EQ((ssize_t)bl2.length(),
1638 ictx->io_work_queue->write((1 << ictx->order) * 10 + 4096 * 10,
1639 bl2.length(), bufferlist{bl2}, 0));
1640
11fdf7f2
TL
1641 ASSERT_EQ(0, ictx->io_work_queue->flush());
1642
1643 ASSERT_EQ(0, ictx->operations->sparsify(4096, no_op));
1644
1645 bufferptr read_ptr(bl.length());
1646 bufferlist read_bl;
1647 read_bl.push_back(read_ptr);
1648
1649 librbd::io::ReadResult read_result{&read_bl};
1650 ASSERT_EQ((ssize_t)read_bl.length(),
1651 ictx->io_work_queue->read((1 << ictx->order) * 10, read_bl.length(),
1652 librbd::io::ReadResult{read_result}, 0));
1653 ASSERT_TRUE(bl.contents_equal(read_bl));
1654
1655 std::string oid = ictx->get_object_name(0);
1656 uint64_t size;
1657 ASSERT_EQ(-ENOENT, ictx->data_ctx.stat(oid, &size, NULL));
1658
81eedcae
TL
1659 oid = ictx->get_object_name(1);
1660 ASSERT_EQ(-ENOENT, ictx->data_ctx.stat(oid, &size, NULL));
11fdf7f2
TL
1661
1662 oid = ictx->get_object_name(10);
1663 std::map<uint64_t, uint64_t> m;
81eedcae
TL
1664 std::map<uint64_t, uint64_t> expected_m;
1665 auto read_len = bl.length();
11fdf7f2 1666 bl.clear();
81eedcae
TL
1667 if (sparsify_supported && sparse_read_supported) {
1668 expected_m = {{4096 * 1, 4096}, {4096 * 3, 4096}};
1669 bl.append(std::string(4096, '1'));
1670 bl.append(std::string(4096, '2'));
1671 } else {
1672 expected_m = {{0, 4096 * 4}};
1673 bl.append(std::string(4096, '\0'));
1674 bl.append(std::string(4096, '1'));
1675 bl.append(std::string(4096, '\0'));
1676 bl.append(std::string(4096, '2'));
1677 }
1678 read_bl.clear();
1679 EXPECT_EQ(static_cast<int>(expected_m.size()),
1680 ictx->data_ctx.sparse_read(oid, m, read_bl, read_len, 0));
1681 EXPECT_EQ(m, expected_m);
1682 EXPECT_TRUE(bl.contents_equal(read_bl));
11fdf7f2
TL
1683}
1684
1685
1686TEST_F(TestInternal, SparsifyClone) {
1687 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
1688
1689 librbd::ImageCtx *ictx;
1690 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1691
81eedcae
TL
1692 bool sparsify_supported = is_sparsify_supported(ictx->data_ctx,
1693 ictx->get_object_name(10));
1694 std::cout << "sparsify_supported=" << sparsify_supported << std::endl;
11fdf7f2
TL
1695
1696 librbd::NoOpProgressContext no_op;
1697 ASSERT_EQ(0, ictx->operations->resize((1 << ictx->order) * 10, true, no_op));
1698
1699 ASSERT_EQ(0, create_snapshot("snap", true));
1700 std::string clone_name = get_temp_image_name();
1701 int order = ictx->order;
1702 ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap", m_ioctx,
1703 clone_name.c_str(), ictx->features, &order, 0, 0));
1704 close_image(ictx);
1705
1706 ASSERT_EQ(0, open_image(clone_name, &ictx));
1707
1708 BOOST_SCOPE_EXIT_ALL(this, &ictx, clone_name) {
1709 close_image(ictx);
1710 librbd::NoOpProgressContext no_op;
1711 EXPECT_EQ(0, librbd::api::Image<>::remove(m_ioctx, clone_name, no_op));
1712 };
1713
1714 ASSERT_EQ(0, ictx->operations->resize((1 << ictx->order) * 20, true, no_op));
1715
1716 bufferlist bl;
1717 bl.append(std::string(4096, '\0'));
1718
1719 ASSERT_EQ((ssize_t)bl.length(),
1720 ictx->io_work_queue->write(0, bl.length(), bufferlist{bl}, 0));
1721
1722 bl.append(std::string(4096, '1'));
1723 bl.append(std::string(4096, '\0'));
1724 bl.append(std::string(4096, '2'));
1725 bl.append(std::string(4096, '\0'));
1726 ASSERT_EQ((ssize_t)bl.length(),
1727 ictx->io_work_queue->write((1 << ictx->order) * 10, bl.length(),
1728 bufferlist{bl}, 0));
1729 ASSERT_EQ(0, ictx->io_work_queue->flush());
1730
1731 ASSERT_EQ(0, ictx->operations->sparsify(4096, no_op));
1732
1733 bufferptr read_ptr(bl.length());
1734 bufferlist read_bl;
1735 read_bl.push_back(read_ptr);
1736
1737 librbd::io::ReadResult read_result{&read_bl};
1738 ASSERT_EQ((ssize_t)read_bl.length(),
1739 ictx->io_work_queue->read((1 << ictx->order) * 10, read_bl.length(),
1740 librbd::io::ReadResult{read_result}, 0));
1741 ASSERT_TRUE(bl.contents_equal(read_bl));
1742
1743 std::string oid = ictx->get_object_name(0);
1744 uint64_t size;
1745 ASSERT_EQ(0, ictx->data_ctx.stat(oid, &size, NULL));
1746 ASSERT_EQ(0, ictx->data_ctx.read(oid, read_bl, 4096, 0));
11fdf7f2 1747}
eafe8130
TL
1748
1749TEST_F(TestInternal, MissingDataPool) {
1750 REQUIRE_FORMAT_V2();
1751
1752 librbd::ImageCtx *ictx;
1753 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1754 ASSERT_EQ(0, snap_create(*ictx, "snap1"));
1755 std::string header_oid = ictx->header_oid;
1756 close_image(ictx);
1757
1758 // emulate non-existent data pool
1759 int64_t pool_id = 1234;
1760 std::string pool_name;
1761 int r;
1762 while ((r = _rados.pool_reverse_lookup(pool_id, &pool_name)) == 0) {
1763 pool_id++;
1764 }
1765 ASSERT_EQ(r, -ENOENT);
1766 bufferlist bl;
1767 using ceph::encode;
1768 encode(pool_id, bl);
1769 ASSERT_EQ(0, m_ioctx.omap_set(header_oid, {{"data_pool_id", bl}}));
1770
1771 ASSERT_EQ(0, open_image(m_image_name, &ictx));
1772
1773 ASSERT_FALSE(ictx->data_ctx.is_valid());
1774 ASSERT_EQ(pool_id, librbd::api::Image<>::get_data_pool_id(ictx));
1775
1776 librbd::image_info_t info;
1777 ASSERT_EQ(0, librbd::info(ictx, info, sizeof(info)));
1778
1779 vector<librbd::snap_info_t> snaps;
9f95a23c 1780 EXPECT_EQ(0, librbd::api::Snapshot<>::list(ictx, snaps));
eafe8130
TL
1781 EXPECT_EQ(1U, snaps.size());
1782 EXPECT_EQ("snap1", snaps[0].name);
1783
1784 bufferptr read_ptr(256);
1785 bufferlist read_bl;
1786 read_bl.push_back(read_ptr);
1787 librbd::io::ReadResult read_result{&read_bl};
1788 ASSERT_EQ(-ENODEV,
1789 ictx->io_work_queue->read(0, 256,
1790 librbd::io::ReadResult{read_result}, 0));
1791 ASSERT_EQ(-ENODEV,
1792 ictx->io_work_queue->write(0, bl.length(), bufferlist{bl}, 0));
1793 ASSERT_EQ(-ENODEV, ictx->io_work_queue->discard(0, 1, 256));
1794 ASSERT_EQ(-ENODEV,
1795 ictx->io_work_queue->writesame(0, bl.length(), bufferlist{bl}, 0));
1796 uint64_t mismatch_off;
1797 ASSERT_EQ(-ENODEV,
1798 ictx->io_work_queue->compare_and_write(0, bl.length(),
1799 bufferlist{bl},
1800 bufferlist{bl},
1801 &mismatch_off, 0));
1802 ASSERT_EQ(-ENODEV, ictx->io_work_queue->flush());
1803
1804 ASSERT_EQ(-ENODEV, snap_create(*ictx, "snap2"));
1805 ASSERT_EQ(0, ictx->operations->snap_remove(cls::rbd::UserSnapshotNamespace(),
1806 "snap1"));
1807
1808 librbd::NoOpProgressContext no_op;
1809 ASSERT_EQ(-ENODEV, ictx->operations->resize(0, true, no_op));
1810
1811 close_image(ictx);
1812
1813 ASSERT_EQ(0, librbd::api::Image<>::remove(m_ioctx, m_image_name, no_op));
1814
1815 ASSERT_EQ(0, create_image_pp(m_rbd, m_ioctx, m_image_name, m_image_size));
1816}