]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/journal/test_Replay.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / test / librbd / journal / test_Replay.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "test/librbd/test_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "cls/rbd/cls_rbd_types.h"
7 #include "cls/journal/cls_journal_types.h"
8 #include "cls/journal/cls_journal_client.h"
9 #include "journal/Journaler.h"
10 #include "librbd/ExclusiveLock.h"
11 #include "librbd/ImageCtx.h"
12 #include "librbd/ImageState.h"
13 #include "librbd/ImageWatcher.h"
14 #include "librbd/internal.h"
15 #include "librbd/Journal.h"
16 #include "librbd/Operations.h"
17 #include "librbd/io/AioCompletion.h"
18 #include "librbd/io/ImageDispatchSpec.h"
19 #include "librbd/io/ImageRequest.h"
20 #include "librbd/io/ImageRequestWQ.h"
21 #include "librbd/io/ReadResult.h"
22 #include "librbd/journal/Types.h"
23
24 void register_test_journal_replay() {
25 }
26
27 class TestJournalReplay : public TestFixture {
28 public:
29
30 int when_acquired_lock(librbd::ImageCtx *ictx) {
31 C_SaferCond lock_ctx;
32 {
33 RWLock::WLocker owner_locker(ictx->owner_lock);
34 ictx->exclusive_lock->acquire_lock(&lock_ctx);
35 }
36 int r = lock_ctx.wait();
37 if (r < 0) {
38 return r;
39 }
40
41 C_SaferCond refresh_ctx;
42 ictx->state->refresh(&refresh_ctx);
43 return refresh_ctx.wait();
44 }
45
46 template<typename T>
47 void inject_into_journal(librbd::ImageCtx *ictx, T event) {
48 C_SaferCond ctx;
49 librbd::journal::EventEntry event_entry(event);
50 {
51 RWLock::RLocker owner_locker(ictx->owner_lock);
52 uint64_t tid = ictx->journal->append_io_event(std::move(event_entry),0, 0,
53 true, 0);
54 ictx->journal->wait_event(tid, &ctx);
55 }
56 ASSERT_EQ(0, ctx.wait());
57 }
58
59 void get_journal_commit_position(librbd::ImageCtx *ictx, int64_t *tag,
60 int64_t *entry)
61 {
62 const std::string client_id = "";
63 std::string journal_id = ictx->id;
64
65 C_SaferCond close_cond;
66 ictx->journal->close(&close_cond);
67 ASSERT_EQ(0, close_cond.wait());
68 delete ictx->journal;
69 ictx->journal = nullptr;
70
71 C_SaferCond cond;
72 uint64_t minimum_set;
73 uint64_t active_set;
74 std::set<cls::journal::Client> registered_clients;
75 std::string oid = ::journal::Journaler::header_oid(journal_id);
76 cls::journal::client::get_mutable_metadata(ictx->md_ctx, oid, &minimum_set,
77 &active_set, &registered_clients, &cond);
78 ASSERT_EQ(0, cond.wait());
79 std::set<cls::journal::Client>::const_iterator c;
80 for (c = registered_clients.begin(); c != registered_clients.end(); ++c) {
81 if (c->id == client_id) {
82 break;
83 }
84 }
85 if (c == registered_clients.end() ||
86 c->commit_position.object_positions.empty()) {
87 *tag = 0;
88 *entry = -1;
89 } else {
90 const cls::journal::ObjectPosition &object_position =
91 *c->commit_position.object_positions.begin();
92 *tag = object_position.tag_tid;
93 *entry = object_position.entry_tid;
94 }
95
96 C_SaferCond open_cond;
97 ictx->journal = new librbd::Journal<>(*ictx);
98 ictx->journal->open(&open_cond);
99 ASSERT_EQ(0, open_cond.wait());
100 }
101 };
102
103 TEST_F(TestJournalReplay, AioDiscardEvent) {
104 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
105
106 // write to the image w/o using the journal
107 librbd::ImageCtx *ictx;
108 ASSERT_EQ(0, open_image(m_image_name, &ictx));
109 ictx->features &= ~RBD_FEATURE_JOURNALING;
110
111 std::string payload(4096, '1');
112 bufferlist payload_bl;
113 payload_bl.append(payload);
114 auto aio_comp = new librbd::io::AioCompletion();
115 ictx->io_work_queue->aio_write(aio_comp, 0, payload.size(),
116 std::move(payload_bl), 0);
117 ASSERT_EQ(0, aio_comp->wait_for_complete());
118 aio_comp->release();
119
120 aio_comp = new librbd::io::AioCompletion();
121 ictx->io_work_queue->aio_flush(aio_comp);
122 ASSERT_EQ(0, aio_comp->wait_for_complete());
123 aio_comp->release();
124
125 std::string read_payload(4096, '\0');
126 librbd::io::ReadResult read_result{&read_payload[0], read_payload.size()};
127 aio_comp = new librbd::io::AioCompletion();
128 ictx->io_work_queue->aio_read(aio_comp, 0, read_payload.size(),
129 librbd::io::ReadResult{read_result}, 0);
130 ASSERT_EQ(0, aio_comp->wait_for_complete());
131 aio_comp->release();
132 ASSERT_EQ(payload, read_payload);
133 close_image(ictx);
134
135 ASSERT_EQ(0, open_image(m_image_name, &ictx));
136 ASSERT_EQ(0, when_acquired_lock(ictx));
137
138 // get current commit position
139 int64_t initial_tag;
140 int64_t initial_entry;
141 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
142
143 // inject a discard operation into the journal
144 inject_into_journal(ictx,
145 librbd::journal::AioDiscardEvent(
146 0, payload.size(), ictx->discard_granularity_bytes));
147 close_image(ictx);
148
149 // re-open the journal so that it replays the new entry
150 ASSERT_EQ(0, open_image(m_image_name, &ictx));
151 ASSERT_EQ(0, when_acquired_lock(ictx));
152
153 aio_comp = new librbd::io::AioCompletion();
154 ictx->io_work_queue->aio_read(aio_comp, 0, read_payload.size(),
155 librbd::io::ReadResult{read_result}, 0);
156 ASSERT_EQ(0, aio_comp->wait_for_complete());
157 aio_comp->release();
158 if (ictx->discard_granularity_bytes > 0) {
159 ASSERT_EQ(payload, read_payload);
160 } else {
161 ASSERT_EQ(std::string(read_payload.size(), '\0'), read_payload);
162 }
163
164 // check the commit position is properly updated
165 int64_t current_tag;
166 int64_t current_entry;
167 get_journal_commit_position(ictx, &current_tag, &current_entry);
168 ASSERT_EQ(initial_tag + 1, current_tag);
169 ASSERT_EQ(0, current_entry);
170
171 // replay several envents and check the commit position
172 inject_into_journal(ictx,
173 librbd::journal::AioDiscardEvent(
174 0, payload.size(), ictx->discard_granularity_bytes));
175 inject_into_journal(ictx,
176 librbd::journal::AioDiscardEvent(
177 0, payload.size(), ictx->discard_granularity_bytes));
178 close_image(ictx);
179
180 ASSERT_EQ(0, open_image(m_image_name, &ictx));
181 ASSERT_EQ(0, when_acquired_lock(ictx));
182 get_journal_commit_position(ictx, &current_tag, &current_entry);
183 ASSERT_EQ(initial_tag + 2, current_tag);
184 ASSERT_EQ(1, current_entry);
185
186 // verify lock ordering constraints
187 aio_comp = new librbd::io::AioCompletion();
188 ictx->io_work_queue->aio_discard(aio_comp, 0, read_payload.size(),
189 ictx->discard_granularity_bytes);
190 ASSERT_EQ(0, aio_comp->wait_for_complete());
191 aio_comp->release();
192 }
193
194 TEST_F(TestJournalReplay, AioWriteEvent) {
195 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
196
197 librbd::ImageCtx *ictx;
198 ASSERT_EQ(0, open_image(m_image_name, &ictx));
199 ASSERT_EQ(0, when_acquired_lock(ictx));
200
201 // get current commit position
202 int64_t initial_tag;
203 int64_t initial_entry;
204 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
205
206 // inject a write operation into the journal
207 std::string payload(4096, '1');
208 bufferlist payload_bl;
209 payload_bl.append(payload);
210 inject_into_journal(ictx,
211 librbd::journal::AioWriteEvent(0, payload.size(), payload_bl));
212 close_image(ictx);
213
214 // re-open the journal so that it replays the new entry
215 ASSERT_EQ(0, open_image(m_image_name, &ictx));
216 ASSERT_EQ(0, when_acquired_lock(ictx));
217
218 std::string read_payload(4096, '\0');
219 librbd::io::ReadResult read_result{&read_payload[0], read_payload.size()};
220 auto aio_comp = new librbd::io::AioCompletion();
221 ictx->io_work_queue->aio_read(aio_comp, 0, read_payload.size(),
222 std::move(read_result), 0);
223 ASSERT_EQ(0, aio_comp->wait_for_complete());
224 aio_comp->release();
225 ASSERT_EQ(payload, read_payload);
226
227 // check the commit position is properly updated
228 int64_t current_tag;
229 int64_t current_entry;
230 get_journal_commit_position(ictx, &current_tag, &current_entry);
231 ASSERT_EQ(initial_tag + 1, current_tag);
232 ASSERT_EQ(0, current_entry);
233
234 // replay several events and check the commit position
235 inject_into_journal(ictx,
236 librbd::journal::AioWriteEvent(0, payload.size(), payload_bl));
237 inject_into_journal(ictx,
238 librbd::journal::AioWriteEvent(0, payload.size(), payload_bl));
239 close_image(ictx);
240
241 ASSERT_EQ(0, open_image(m_image_name, &ictx));
242 ASSERT_EQ(0, when_acquired_lock(ictx));
243 get_journal_commit_position(ictx, &current_tag, &current_entry);
244 ASSERT_EQ(initial_tag + 2, current_tag);
245 ASSERT_EQ(1, current_entry);
246
247 // verify lock ordering constraints
248 aio_comp = new librbd::io::AioCompletion();
249 ictx->io_work_queue->aio_write(aio_comp, 0, payload.size(),
250 bufferlist{payload_bl}, 0);
251 ASSERT_EQ(0, aio_comp->wait_for_complete());
252 aio_comp->release();
253 }
254
255 TEST_F(TestJournalReplay, AioFlushEvent) {
256 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
257
258 librbd::ImageCtx *ictx;
259
260 ASSERT_EQ(0, open_image(m_image_name, &ictx));
261 ASSERT_EQ(0, when_acquired_lock(ictx));
262
263 // get current commit position
264 int64_t initial_tag;
265 int64_t initial_entry;
266 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
267
268 // inject a flush operation into the journal
269 inject_into_journal(ictx, librbd::journal::AioFlushEvent());
270 close_image(ictx);
271
272 // re-open the journal so that it replays the new entry
273 ASSERT_EQ(0, open_image(m_image_name, &ictx));
274 ASSERT_EQ(0, when_acquired_lock(ictx));
275
276 // check the commit position is properly updated
277 int64_t current_tag;
278 int64_t current_entry;
279 get_journal_commit_position(ictx, &current_tag, &current_entry);
280 ASSERT_EQ(initial_tag + 1, current_tag);
281 ASSERT_EQ(0, current_entry);
282
283 // replay several events and check the commit position
284 inject_into_journal(ictx, librbd::journal::AioFlushEvent());
285 inject_into_journal(ictx, librbd::journal::AioFlushEvent());
286 close_image(ictx);
287
288 ASSERT_EQ(0, open_image(m_image_name, &ictx));
289 ASSERT_EQ(0, when_acquired_lock(ictx));
290 get_journal_commit_position(ictx, &current_tag, &current_entry);
291 ASSERT_EQ(initial_tag + 2, current_tag);
292 ASSERT_EQ(1, current_entry);
293
294 // verify lock ordering constraints
295 auto aio_comp = new librbd::io::AioCompletion();
296 ictx->io_work_queue->aio_flush(aio_comp);
297 ASSERT_EQ(0, aio_comp->wait_for_complete());
298 aio_comp->release();
299 }
300
301 TEST_F(TestJournalReplay, SnapCreate) {
302 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
303
304 librbd::ImageCtx *ictx;
305
306 ASSERT_EQ(0, open_image(m_image_name, &ictx));
307 ASSERT_EQ(0, when_acquired_lock(ictx));
308
309 // get current commit position
310 int64_t initial_tag;
311 int64_t initial_entry;
312 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
313
314 // inject snapshot ops into journal
315 inject_into_journal(ictx, librbd::journal::SnapCreateEvent(1, cls::rbd::UserSnapshotNamespace(),
316 "snap"));
317 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
318 close_image(ictx);
319
320 // replay journal
321 ASSERT_EQ(0, open_image(m_image_name, &ictx));
322 ASSERT_EQ(0, when_acquired_lock(ictx));
323
324 int64_t current_tag;
325 int64_t current_entry;
326 get_journal_commit_position(ictx, &current_tag, &current_entry);
327 ASSERT_EQ(initial_tag + 1, current_tag);
328 ASSERT_EQ(1, current_entry);
329
330 {
331 RWLock::RLocker snap_locker(ictx->snap_lock);
332 ASSERT_NE(CEPH_NOSNAP, ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(),
333 "snap"));
334 }
335
336 // verify lock ordering constraints
337 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
338 "snap2"));
339 }
340
341 TEST_F(TestJournalReplay, SnapProtect) {
342 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
343
344 librbd::ImageCtx *ictx;
345
346 ASSERT_EQ(0, open_image(m_image_name, &ictx));
347 ASSERT_EQ(0, when_acquired_lock(ictx));
348
349 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
350 "snap"));
351
352 // get current commit position
353 int64_t initial_tag;
354 int64_t initial_entry;
355 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
356
357 // inject snapshot ops into journal
358 inject_into_journal(ictx,
359 librbd::journal::SnapProtectEvent(1,
360 cls::rbd::UserSnapshotNamespace(),
361 "snap"));
362 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
363 close_image(ictx);
364
365 // replay journal
366 ASSERT_EQ(0, open_image(m_image_name, &ictx));
367 ASSERT_EQ(0, when_acquired_lock(ictx));
368
369 int64_t current_tag;
370 int64_t current_entry;
371 get_journal_commit_position(ictx, &current_tag, &current_entry);
372 ASSERT_EQ(initial_tag, current_tag);
373 ASSERT_EQ(initial_entry + 2, current_entry);
374
375 bool is_protected;
376 ASSERT_EQ(0, librbd::snap_is_protected(ictx, "snap", &is_protected));
377 ASSERT_TRUE(is_protected);
378
379 // verify lock ordering constraints
380 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
381 "snap2"));
382 ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
383 "snap2"));
384 }
385
386 TEST_F(TestJournalReplay, SnapUnprotect) {
387 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
388
389 librbd::ImageCtx *ictx;
390
391 ASSERT_EQ(0, open_image(m_image_name, &ictx));
392 ASSERT_EQ(0, when_acquired_lock(ictx));
393
394 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
395 "snap"));
396 uint64_t snap_id;
397 {
398 RWLock::RLocker snap_locker(ictx->snap_lock);
399 snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(), "snap");
400 ASSERT_NE(CEPH_NOSNAP, snap_id);
401 }
402 ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
403 "snap"));
404
405 // get current commit position
406 int64_t initial_tag;
407 int64_t initial_entry;
408 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
409
410 // inject snapshot ops into journal
411 inject_into_journal(ictx,
412 librbd::journal::SnapUnprotectEvent(1,
413 cls::rbd::UserSnapshotNamespace(),
414 "snap"));
415 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
416 close_image(ictx);
417
418 // replay journal
419 ASSERT_EQ(0, open_image(m_image_name, &ictx));
420 ASSERT_EQ(0, when_acquired_lock(ictx));
421
422 int64_t current_tag;
423 int64_t current_entry;
424 get_journal_commit_position(ictx, &current_tag, &current_entry);
425 ASSERT_EQ(initial_tag, current_tag);
426 ASSERT_EQ(initial_entry + 2, current_entry);
427
428 bool is_protected;
429 ASSERT_EQ(0, librbd::snap_is_protected(ictx, "snap", &is_protected));
430 ASSERT_FALSE(is_protected);
431
432 // verify lock ordering constraints
433 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
434 "snap2"));
435 ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
436 "snap2"));
437 ASSERT_EQ(0, ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(),
438 "snap2"));
439 }
440
441 TEST_F(TestJournalReplay, SnapRename) {
442 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
443
444 librbd::ImageCtx *ictx;
445
446 ASSERT_EQ(0, open_image(m_image_name, &ictx));
447 ASSERT_EQ(0, when_acquired_lock(ictx));
448
449 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
450 "snap"));
451 uint64_t snap_id;
452 {
453 RWLock::RLocker snap_locker(ictx->snap_lock);
454 snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(), "snap");
455 ASSERT_NE(CEPH_NOSNAP, snap_id);
456 }
457
458 // get current commit position
459 int64_t initial_tag;
460 int64_t initial_entry;
461 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
462
463 // inject snapshot ops into journal
464 inject_into_journal(ictx, librbd::journal::SnapRenameEvent(1, snap_id, "snap",
465 "snap2"));
466 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
467 close_image(ictx);
468
469 // replay journal
470 ASSERT_EQ(0, open_image(m_image_name, &ictx));
471 ASSERT_EQ(0, when_acquired_lock(ictx));
472
473 int64_t current_tag;
474 int64_t current_entry;
475 get_journal_commit_position(ictx, &current_tag, &current_entry);
476 ASSERT_EQ(initial_tag, current_tag);
477 ASSERT_EQ(initial_entry + 2, current_entry);
478 ASSERT_EQ(0, ictx->state->refresh());
479
480 {
481 RWLock::RLocker snap_locker(ictx->snap_lock);
482 snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(), "snap2");
483 ASSERT_NE(CEPH_NOSNAP, snap_id);
484 }
485
486 // verify lock ordering constraints
487 ASSERT_EQ(0, ictx->operations->snap_rename("snap2", "snap3"));
488 }
489
490 TEST_F(TestJournalReplay, SnapRollback) {
491 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
492
493 librbd::ImageCtx *ictx;
494
495 ASSERT_EQ(0, open_image(m_image_name, &ictx));
496 ASSERT_EQ(0, when_acquired_lock(ictx));
497
498 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
499 "snap"));
500
501 // get current commit position
502 int64_t initial_tag;
503 int64_t initial_entry;
504 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
505
506 // inject snapshot ops into journal
507 inject_into_journal(ictx,
508 librbd::journal::SnapRollbackEvent(1,
509 cls::rbd::UserSnapshotNamespace(),
510 "snap"));
511 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
512 close_image(ictx);
513
514 // replay journal
515 ASSERT_EQ(0, open_image(m_image_name, &ictx));
516 ASSERT_EQ(0, when_acquired_lock(ictx));
517
518 int64_t current_tag;
519 int64_t current_entry;
520 get_journal_commit_position(ictx, &current_tag, &current_entry);
521 ASSERT_EQ(initial_tag, current_tag);
522 ASSERT_EQ(initial_entry + 2, current_entry);
523
524 // verify lock ordering constraints
525 librbd::NoOpProgressContext no_op_progress;
526 ASSERT_EQ(0, ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(),
527 "snap",
528 no_op_progress));
529 }
530
531 TEST_F(TestJournalReplay, SnapRemove) {
532 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
533
534 librbd::ImageCtx *ictx;
535
536 ASSERT_EQ(0, open_image(m_image_name, &ictx));
537 ASSERT_EQ(0, when_acquired_lock(ictx));
538
539 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
540 "snap"));
541
542 // get current commit position
543 int64_t initial_tag;
544 int64_t initial_entry;
545 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
546
547 // inject snapshot ops into journal
548 inject_into_journal(ictx,
549 librbd::journal::SnapRemoveEvent(1,
550 cls::rbd::UserSnapshotNamespace(),
551 "snap"));
552 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
553 close_image(ictx);
554
555 // replay journal
556 ASSERT_EQ(0, open_image(m_image_name, &ictx));
557 ASSERT_EQ(0, when_acquired_lock(ictx));
558
559 int64_t current_tag;
560 int64_t current_entry;
561 get_journal_commit_position(ictx, &current_tag, &current_entry);
562 ASSERT_EQ(initial_tag, current_tag);
563 ASSERT_EQ(initial_entry + 2, current_entry);
564
565 {
566 RWLock::RLocker snap_locker(ictx->snap_lock);
567 uint64_t snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(),
568 "snap");
569 ASSERT_EQ(CEPH_NOSNAP, snap_id);
570 }
571
572 // verify lock ordering constraints
573 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
574 "snap"));
575 ASSERT_EQ(0, ictx->operations->snap_remove(cls::rbd::UserSnapshotNamespace(),
576 "snap"));
577 }
578
579 TEST_F(TestJournalReplay, Rename) {
580 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
581
582 librbd::ImageCtx *ictx;
583
584 ASSERT_EQ(0, open_image(m_image_name, &ictx));
585 ASSERT_EQ(0, when_acquired_lock(ictx));
586
587 // get current commit position
588 int64_t initial_tag;
589 int64_t initial_entry;
590 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
591
592 // inject snapshot ops into journal
593 std::string new_image_name(get_temp_image_name());
594 inject_into_journal(ictx, librbd::journal::RenameEvent(1, new_image_name));
595 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
596 close_image(ictx);
597
598 // replay journal
599 ASSERT_EQ(0, open_image(m_image_name, &ictx));
600 ASSERT_EQ(0, when_acquired_lock(ictx));
601
602 int64_t current_tag;
603 int64_t current_entry;
604 get_journal_commit_position(ictx, &current_tag, &current_entry);
605 ASSERT_EQ(initial_tag + 1, current_tag);
606 ASSERT_EQ(1, current_entry);
607
608 // verify lock ordering constraints
609 librbd::RBD rbd;
610 ASSERT_EQ(0, rbd.rename(m_ioctx, new_image_name.c_str(), m_image_name.c_str()));
611 }
612
613 TEST_F(TestJournalReplay, Resize) {
614 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
615
616 librbd::ImageCtx *ictx;
617
618 ASSERT_EQ(0, open_image(m_image_name, &ictx));
619 ASSERT_EQ(0, when_acquired_lock(ictx));
620
621 // get current commit position
622 int64_t initial_tag;
623 int64_t initial_entry;
624 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
625
626 // inject snapshot ops into journal
627 inject_into_journal(ictx, librbd::journal::ResizeEvent(1, 16));
628 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
629 close_image(ictx);
630
631 // replay journal
632 ASSERT_EQ(0, open_image(m_image_name, &ictx));
633 ASSERT_EQ(0, when_acquired_lock(ictx));
634
635 int64_t current_tag;
636 int64_t current_entry;
637 get_journal_commit_position(ictx, &current_tag, &current_entry);
638 ASSERT_EQ(initial_tag + 1, current_tag);
639 ASSERT_EQ(1, current_entry);
640
641 // verify lock ordering constraints
642 librbd::NoOpProgressContext no_op_progress;
643 ASSERT_EQ(0, ictx->operations->resize(0, true, no_op_progress));
644 }
645
646 TEST_F(TestJournalReplay, Flatten) {
647 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_JOURNALING);
648
649 librbd::ImageCtx *ictx;
650 ASSERT_EQ(0, open_image(m_image_name, &ictx));
651 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
652 "snap"));
653 ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
654 "snap"));
655
656 std::string clone_name = get_temp_image_name();
657 int order = ictx->order;
658 ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap", m_ioctx,
659 clone_name.c_str(), ictx->features, &order, 0, 0));
660
661 librbd::ImageCtx *ictx2;
662 ASSERT_EQ(0, open_image(clone_name, &ictx2));
663 ASSERT_EQ(0, when_acquired_lock(ictx2));
664
665 // get current commit position
666 int64_t initial_tag;
667 int64_t initial_entry;
668 get_journal_commit_position(ictx2, &initial_tag, &initial_entry);
669
670 // inject snapshot ops into journal
671 inject_into_journal(ictx2, librbd::journal::FlattenEvent(1));
672 inject_into_journal(ictx2, librbd::journal::OpFinishEvent(1, 0));
673 close_image(ictx2);
674
675 // replay journal
676 ASSERT_EQ(0, open_image(clone_name, &ictx2));
677 ASSERT_EQ(0, when_acquired_lock(ictx2));
678
679 int64_t current_tag;
680 int64_t current_entry;
681 get_journal_commit_position(ictx2, &current_tag, &current_entry);
682 ASSERT_EQ(initial_tag + 1, current_tag);
683 ASSERT_EQ(1, current_entry);
684 ASSERT_EQ(0, ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(),
685 "snap"));
686
687 // verify lock ordering constraints
688 librbd::NoOpProgressContext no_op;
689 ASSERT_EQ(-EINVAL, ictx2->operations->flatten(no_op));
690 }
691
692 TEST_F(TestJournalReplay, UpdateFeatures) {
693 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
694
695 librbd::ImageCtx *ictx;
696
697 ASSERT_EQ(0, open_image(m_image_name, &ictx));
698 ASSERT_EQ(0, when_acquired_lock(ictx));
699
700 uint64_t features = RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF;
701 bool enabled = !ictx->test_features(features);
702
703 // get current commit position
704 int64_t initial_tag;
705 int64_t initial_entry;
706 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
707
708 // inject update_features op into journal
709 inject_into_journal(ictx, librbd::journal::UpdateFeaturesEvent(1, features,
710 enabled));
711 close_image(ictx);
712
713 // replay journal
714 ASSERT_EQ(0, open_image(m_image_name, &ictx));
715 ASSERT_EQ(0, when_acquired_lock(ictx));
716
717 int64_t current_tag;
718 int64_t current_entry;
719 get_journal_commit_position(ictx, &current_tag, &current_entry);
720 ASSERT_EQ(initial_tag + 1, current_tag);
721 ASSERT_EQ(0, current_entry);
722
723 ASSERT_EQ(enabled, ictx->test_features(features));
724
725 // verify lock ordering constraints
726 ASSERT_EQ(0, ictx->operations->update_features(features, !enabled));
727 }
728
729 TEST_F(TestJournalReplay, MetadataSet) {
730 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
731
732 librbd::ImageCtx *ictx;
733
734 ASSERT_EQ(0, open_image(m_image_name, &ictx));
735 ASSERT_EQ(0, when_acquired_lock(ictx));
736
737 // get current commit position
738 int64_t initial_tag;
739 int64_t initial_entry;
740 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
741
742 // inject metadata_set op into journal
743 inject_into_journal(ictx, librbd::journal::MetadataSetEvent(
744 1, "conf_rbd_mirroring_replay_delay", "9876"));
745 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
746 close_image(ictx);
747
748 // replay journal
749 ASSERT_EQ(0, open_image(m_image_name, &ictx));
750 ASSERT_EQ(0, when_acquired_lock(ictx));
751
752 int64_t current_tag;
753 int64_t current_entry;
754 get_journal_commit_position(ictx, &current_tag, &current_entry);
755 ASSERT_EQ(initial_tag + 1, current_tag);
756 ASSERT_EQ(1, current_entry);
757
758 ASSERT_EQ(9876U, ictx->mirroring_replay_delay);
759
760 std::string value;
761 ASSERT_EQ(0, librbd::metadata_get(ictx, "conf_rbd_mirroring_replay_delay",
762 &value));
763 ASSERT_EQ("9876", value);
764
765 // verify lock ordering constraints
766 ASSERT_EQ(0, ictx->operations->metadata_set("key2", "value"));
767 }
768
769 TEST_F(TestJournalReplay, MetadataRemove) {
770 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
771
772 librbd::ImageCtx *ictx;
773
774 ASSERT_EQ(0, open_image(m_image_name, &ictx));
775 ASSERT_EQ(0, when_acquired_lock(ictx));
776
777 ASSERT_EQ(0, ictx->operations->metadata_set(
778 "conf_rbd_mirroring_replay_delay", "9876"));
779
780 // get current commit position
781 int64_t initial_tag;
782 int64_t initial_entry;
783 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
784
785 // inject metadata_remove op into journal
786 inject_into_journal(ictx, librbd::journal::MetadataRemoveEvent(
787 1, "conf_rbd_mirroring_replay_delay"));
788 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
789 close_image(ictx);
790
791 // replay journal
792 ASSERT_EQ(0, open_image(m_image_name, &ictx));
793 ASSERT_EQ(0, when_acquired_lock(ictx));
794
795 int64_t current_tag;
796 int64_t current_entry;
797 get_journal_commit_position(ictx, &current_tag, &current_entry);
798 ASSERT_EQ(initial_tag, current_tag);
799 ASSERT_EQ(initial_entry + 2, current_entry);
800 ASSERT_EQ(0U, ictx->mirroring_replay_delay);
801
802 std::string value;
803 ASSERT_EQ(-ENOENT,
804 librbd::metadata_get(ictx, "conf_rbd_mirroring_replay_delay",
805 &value));
806
807 // verify lock ordering constraints
808 ASSERT_EQ(0, ictx->operations->metadata_set("key", "value"));
809 ASSERT_EQ(0, ictx->operations->metadata_remove("key"));
810 }
811
812 TEST_F(TestJournalReplay, ObjectPosition) {
813 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
814
815 librbd::ImageCtx *ictx;
816 ASSERT_EQ(0, open_image(m_image_name, &ictx));
817 ASSERT_EQ(0, when_acquired_lock(ictx));
818
819 // get current commit position
820 int64_t initial_tag;
821 int64_t initial_entry;
822 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
823
824 std::string payload(4096, '1');
825 bufferlist payload_bl;
826 payload_bl.append(payload);
827 auto aio_comp = new librbd::io::AioCompletion();
828 ictx->io_work_queue->aio_write(aio_comp, 0, payload.size(),
829 bufferlist{payload_bl}, 0);
830 ASSERT_EQ(0, aio_comp->wait_for_complete());
831 aio_comp->release();
832
833 aio_comp = new librbd::io::AioCompletion();
834 ictx->io_work_queue->aio_flush(aio_comp);
835 ASSERT_EQ(0, aio_comp->wait_for_complete());
836 aio_comp->release();
837
838 // check the commit position updated
839 int64_t current_tag;
840 int64_t current_entry;
841 get_journal_commit_position(ictx, &current_tag, &current_entry);
842 ASSERT_EQ(initial_tag + 1, current_tag);
843 ASSERT_EQ(1, current_entry);
844
845 // write again
846
847 aio_comp = new librbd::io::AioCompletion();
848 ictx->io_work_queue->aio_write(aio_comp, 0, payload.size(),
849 bufferlist{payload_bl}, 0);
850 ASSERT_EQ(0, aio_comp->wait_for_complete());
851 aio_comp->release();
852
853 aio_comp = new librbd::io::AioCompletion();
854 ictx->io_work_queue->aio_flush(aio_comp);
855 ASSERT_EQ(0, aio_comp->wait_for_complete());
856 aio_comp->release();
857
858 // user flush requests are ignored when journaling + cache are enabled
859 C_SaferCond flush_ctx;
860 aio_comp = librbd::io::AioCompletion::create(
861 &flush_ctx, ictx, librbd::io::AIO_TYPE_FLUSH);
862 auto req = librbd::io::ImageDispatchSpec<>::create_flush_request(
863 *ictx, aio_comp, librbd::io::FLUSH_SOURCE_INTERNAL, {});
864 req->send();
865 delete req;
866 ASSERT_EQ(0, flush_ctx.wait());
867
868 // check the commit position updated
869 get_journal_commit_position(ictx, &current_tag, &current_entry);
870 ASSERT_EQ(initial_tag + 1, current_tag);
871 ASSERT_EQ(3, current_entry);
872 }