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