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