]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/journal/test_Replay.cc
7c735695b8e89fae73fbcbbeaf5ac3e555318e73
[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 "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
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 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
104 TEST_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,
146 librbd::journal::AioDiscardEvent(0, payload.size(), ictx->skip_partial_discard));
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->cct->_conf->rbd_skip_partial_discard) {
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(0, payload.size(), ictx->cct->_conf->rbd_skip_partial_discard));
174 inject_into_journal(ictx,
175 librbd::journal::AioDiscardEvent(0, payload.size(), ictx->cct->_conf->rbd_skip_partial_discard));
176 close_image(ictx);
177
178 ASSERT_EQ(0, open_image(m_image_name, &ictx));
179 ASSERT_EQ(0, when_acquired_lock(ictx));
180 get_journal_commit_position(ictx, &current_tag, &current_entry);
181 ASSERT_EQ(initial_tag + 2, current_tag);
182 ASSERT_EQ(1, current_entry);
183
184 // verify lock ordering constraints
185 aio_comp = new librbd::io::AioCompletion();
186 ictx->io_work_queue->aio_discard(aio_comp, 0, read_payload.size(), ictx->cct->_conf->rbd_skip_partial_discard);
187 ASSERT_EQ(0, aio_comp->wait_for_complete());
188 aio_comp->release();
189 }
190
191 TEST_F(TestJournalReplay, AioWriteEvent) {
192 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
193
194 librbd::ImageCtx *ictx;
195 ASSERT_EQ(0, open_image(m_image_name, &ictx));
196 ASSERT_EQ(0, when_acquired_lock(ictx));
197
198 // get current commit position
199 int64_t initial_tag;
200 int64_t initial_entry;
201 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
202
203 // inject a write operation into the journal
204 std::string payload(4096, '1');
205 bufferlist payload_bl;
206 payload_bl.append(payload);
207 inject_into_journal(ictx,
208 librbd::journal::AioWriteEvent(0, payload.size(), payload_bl));
209 close_image(ictx);
210
211 // re-open the journal so that it replays the new entry
212 ASSERT_EQ(0, open_image(m_image_name, &ictx));
213 ASSERT_EQ(0, when_acquired_lock(ictx));
214
215 std::string read_payload(4096, '\0');
216 librbd::io::ReadResult read_result{&read_payload[0], read_payload.size()};
217 auto aio_comp = new librbd::io::AioCompletion();
218 ictx->io_work_queue->aio_read(aio_comp, 0, read_payload.size(),
219 std::move(read_result), 0);
220 ASSERT_EQ(0, aio_comp->wait_for_complete());
221 aio_comp->release();
222 ASSERT_EQ(payload, read_payload);
223
224 // check the commit position is properly updated
225 int64_t current_tag;
226 int64_t current_entry;
227 get_journal_commit_position(ictx, &current_tag, &current_entry);
228 ASSERT_EQ(initial_tag + 1, current_tag);
229 ASSERT_EQ(0, current_entry);
230
231 // replay several events and check the commit position
232 inject_into_journal(ictx,
233 librbd::journal::AioWriteEvent(0, payload.size(), payload_bl));
234 inject_into_journal(ictx,
235 librbd::journal::AioWriteEvent(0, payload.size(), payload_bl));
236 close_image(ictx);
237
238 ASSERT_EQ(0, open_image(m_image_name, &ictx));
239 ASSERT_EQ(0, when_acquired_lock(ictx));
240 get_journal_commit_position(ictx, &current_tag, &current_entry);
241 ASSERT_EQ(initial_tag + 2, current_tag);
242 ASSERT_EQ(1, current_entry);
243
244 // verify lock ordering constraints
245 aio_comp = new librbd::io::AioCompletion();
246 ictx->io_work_queue->aio_write(aio_comp, 0, payload.size(),
247 bufferlist{payload_bl}, 0);
248 ASSERT_EQ(0, aio_comp->wait_for_complete());
249 aio_comp->release();
250 }
251
252 TEST_F(TestJournalReplay, AioFlushEvent) {
253 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
254
255 librbd::ImageCtx *ictx;
256
257 ASSERT_EQ(0, open_image(m_image_name, &ictx));
258 ASSERT_EQ(0, when_acquired_lock(ictx));
259
260 // get current commit position
261 int64_t initial_tag;
262 int64_t initial_entry;
263 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
264
265 // inject a flush operation into the journal
266 inject_into_journal(ictx, librbd::journal::AioFlushEvent());
267 close_image(ictx);
268
269 // re-open the journal so that it replays the new entry
270 ASSERT_EQ(0, open_image(m_image_name, &ictx));
271 ASSERT_EQ(0, when_acquired_lock(ictx));
272
273 // check the commit position is properly updated
274 int64_t current_tag;
275 int64_t current_entry;
276 get_journal_commit_position(ictx, &current_tag, &current_entry);
277 ASSERT_EQ(initial_tag + 1, current_tag);
278 ASSERT_EQ(0, current_entry);
279
280 // replay several events and check the commit position
281 inject_into_journal(ictx, librbd::journal::AioFlushEvent());
282 inject_into_journal(ictx, librbd::journal::AioFlushEvent());
283 close_image(ictx);
284
285 ASSERT_EQ(0, open_image(m_image_name, &ictx));
286 ASSERT_EQ(0, when_acquired_lock(ictx));
287 get_journal_commit_position(ictx, &current_tag, &current_entry);
288 ASSERT_EQ(initial_tag + 2, current_tag);
289 ASSERT_EQ(1, current_entry);
290
291 // verify lock ordering constraints
292 auto aio_comp = new librbd::io::AioCompletion();
293 ictx->io_work_queue->aio_flush(aio_comp);
294 ASSERT_EQ(0, aio_comp->wait_for_complete());
295 aio_comp->release();
296 }
297
298 TEST_F(TestJournalReplay, SnapCreate) {
299 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
300
301 librbd::ImageCtx *ictx;
302
303 ASSERT_EQ(0, open_image(m_image_name, &ictx));
304 ASSERT_EQ(0, when_acquired_lock(ictx));
305
306 // get current commit position
307 int64_t initial_tag;
308 int64_t initial_entry;
309 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
310
311 // inject snapshot ops into journal
312 inject_into_journal(ictx, librbd::journal::SnapCreateEvent(1, cls::rbd::UserSnapshotNamespace(),
313 "snap"));
314 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
315 close_image(ictx);
316
317 // replay journal
318 ASSERT_EQ(0, open_image(m_image_name, &ictx));
319 ASSERT_EQ(0, when_acquired_lock(ictx));
320
321 int64_t current_tag;
322 int64_t current_entry;
323 get_journal_commit_position(ictx, &current_tag, &current_entry);
324 ASSERT_EQ(initial_tag + 1, current_tag);
325 ASSERT_EQ(1, current_entry);
326
327 {
328 RWLock::RLocker snap_locker(ictx->snap_lock);
329 ASSERT_NE(CEPH_NOSNAP, ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(),
330 "snap"));
331 }
332
333 // verify lock ordering constraints
334 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
335 "snap2"));
336 }
337
338 TEST_F(TestJournalReplay, SnapProtect) {
339 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
340
341 librbd::ImageCtx *ictx;
342
343 ASSERT_EQ(0, open_image(m_image_name, &ictx));
344 ASSERT_EQ(0, when_acquired_lock(ictx));
345
346 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
347 "snap"));
348
349 // get current commit position
350 int64_t initial_tag;
351 int64_t initial_entry;
352 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
353
354 // inject snapshot ops into journal
355 inject_into_journal(ictx,
356 librbd::journal::SnapProtectEvent(1,
357 cls::rbd::UserSnapshotNamespace(),
358 "snap"));
359 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
360 close_image(ictx);
361
362 // replay journal
363 ASSERT_EQ(0, open_image(m_image_name, &ictx));
364 ASSERT_EQ(0, when_acquired_lock(ictx));
365
366 int64_t current_tag;
367 int64_t current_entry;
368 get_journal_commit_position(ictx, &current_tag, &current_entry);
369 ASSERT_EQ(initial_tag, current_tag);
370 ASSERT_EQ(initial_entry + 2, current_entry);
371
372 bool is_protected;
373 ASSERT_EQ(0, librbd::snap_is_protected(ictx, "snap", &is_protected));
374 ASSERT_TRUE(is_protected);
375
376 // verify lock ordering constraints
377 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
378 "snap2"));
379 ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
380 "snap2"));
381 }
382
383 TEST_F(TestJournalReplay, SnapUnprotect) {
384 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
385
386 librbd::ImageCtx *ictx;
387
388 ASSERT_EQ(0, open_image(m_image_name, &ictx));
389 ASSERT_EQ(0, when_acquired_lock(ictx));
390
391 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
392 "snap"));
393 uint64_t snap_id;
394 {
395 RWLock::RLocker snap_locker(ictx->snap_lock);
396 snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(), "snap");
397 ASSERT_NE(CEPH_NOSNAP, snap_id);
398 }
399 ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
400 "snap"));
401
402 // get current commit position
403 int64_t initial_tag;
404 int64_t initial_entry;
405 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
406
407 // inject snapshot ops into journal
408 inject_into_journal(ictx,
409 librbd::journal::SnapUnprotectEvent(1,
410 cls::rbd::UserSnapshotNamespace(),
411 "snap"));
412 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
413 close_image(ictx);
414
415 // replay journal
416 ASSERT_EQ(0, open_image(m_image_name, &ictx));
417 ASSERT_EQ(0, when_acquired_lock(ictx));
418
419 int64_t current_tag;
420 int64_t current_entry;
421 get_journal_commit_position(ictx, &current_tag, &current_entry);
422 ASSERT_EQ(initial_tag, current_tag);
423 ASSERT_EQ(initial_entry + 2, current_entry);
424
425 bool is_protected;
426 ASSERT_EQ(0, librbd::snap_is_protected(ictx, "snap", &is_protected));
427 ASSERT_FALSE(is_protected);
428
429 // verify lock ordering constraints
430 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
431 "snap2"));
432 ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
433 "snap2"));
434 ASSERT_EQ(0, ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(),
435 "snap2"));
436 }
437
438 TEST_F(TestJournalReplay, SnapRename) {
439 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
440
441 librbd::ImageCtx *ictx;
442
443 ASSERT_EQ(0, open_image(m_image_name, &ictx));
444 ASSERT_EQ(0, when_acquired_lock(ictx));
445
446 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
447 "snap"));
448 uint64_t snap_id;
449 {
450 RWLock::RLocker snap_locker(ictx->snap_lock);
451 snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(), "snap");
452 ASSERT_NE(CEPH_NOSNAP, snap_id);
453 }
454
455 // get current commit position
456 int64_t initial_tag;
457 int64_t initial_entry;
458 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
459
460 // inject snapshot ops into journal
461 inject_into_journal(ictx, librbd::journal::SnapRenameEvent(1, snap_id, "snap",
462 "snap2"));
463 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
464 close_image(ictx);
465
466 // replay journal
467 ASSERT_EQ(0, open_image(m_image_name, &ictx));
468 ASSERT_EQ(0, when_acquired_lock(ictx));
469
470 int64_t current_tag;
471 int64_t current_entry;
472 get_journal_commit_position(ictx, &current_tag, &current_entry);
473 ASSERT_EQ(initial_tag, current_tag);
474 ASSERT_EQ(initial_entry + 2, current_entry);
475 ASSERT_EQ(0, ictx->state->refresh());
476
477 {
478 RWLock::RLocker snap_locker(ictx->snap_lock);
479 snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(), "snap2");
480 ASSERT_NE(CEPH_NOSNAP, snap_id);
481 }
482
483 // verify lock ordering constraints
484 ASSERT_EQ(0, ictx->operations->snap_rename("snap2", "snap3"));
485 }
486
487 TEST_F(TestJournalReplay, SnapRollback) {
488 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
489
490 librbd::ImageCtx *ictx;
491
492 ASSERT_EQ(0, open_image(m_image_name, &ictx));
493 ASSERT_EQ(0, when_acquired_lock(ictx));
494
495 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
496 "snap"));
497
498 // get current commit position
499 int64_t initial_tag;
500 int64_t initial_entry;
501 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
502
503 // inject snapshot ops into journal
504 inject_into_journal(ictx,
505 librbd::journal::SnapRollbackEvent(1,
506 cls::rbd::UserSnapshotNamespace(),
507 "snap"));
508 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
509 close_image(ictx);
510
511 // replay journal
512 ASSERT_EQ(0, open_image(m_image_name, &ictx));
513 ASSERT_EQ(0, when_acquired_lock(ictx));
514
515 int64_t current_tag;
516 int64_t current_entry;
517 get_journal_commit_position(ictx, &current_tag, &current_entry);
518 ASSERT_EQ(initial_tag, current_tag);
519 ASSERT_EQ(initial_entry + 2, current_entry);
520
521 // verify lock ordering constraints
522 librbd::NoOpProgressContext no_op_progress;
523 ASSERT_EQ(0, ictx->operations->snap_rollback(cls::rbd::UserSnapshotNamespace(),
524 "snap",
525 no_op_progress));
526 }
527
528 TEST_F(TestJournalReplay, SnapRemove) {
529 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
530
531 librbd::ImageCtx *ictx;
532
533 ASSERT_EQ(0, open_image(m_image_name, &ictx));
534 ASSERT_EQ(0, when_acquired_lock(ictx));
535
536 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
537 "snap"));
538
539 // get current commit position
540 int64_t initial_tag;
541 int64_t initial_entry;
542 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
543
544 // inject snapshot ops into journal
545 inject_into_journal(ictx,
546 librbd::journal::SnapRemoveEvent(1,
547 cls::rbd::UserSnapshotNamespace(),
548 "snap"));
549 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
550 close_image(ictx);
551
552 // replay journal
553 ASSERT_EQ(0, open_image(m_image_name, &ictx));
554 ASSERT_EQ(0, when_acquired_lock(ictx));
555
556 int64_t current_tag;
557 int64_t current_entry;
558 get_journal_commit_position(ictx, &current_tag, &current_entry);
559 ASSERT_EQ(initial_tag, current_tag);
560 ASSERT_EQ(initial_entry + 2, current_entry);
561
562 {
563 RWLock::RLocker snap_locker(ictx->snap_lock);
564 uint64_t snap_id = ictx->get_snap_id(cls::rbd::UserSnapshotNamespace(),
565 "snap");
566 ASSERT_EQ(CEPH_NOSNAP, snap_id);
567 }
568
569 // verify lock ordering constraints
570 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
571 "snap"));
572 ASSERT_EQ(0, ictx->operations->snap_remove(cls::rbd::UserSnapshotNamespace(),
573 "snap"));
574 }
575
576 TEST_F(TestJournalReplay, Rename) {
577 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
578
579 librbd::ImageCtx *ictx;
580
581 ASSERT_EQ(0, open_image(m_image_name, &ictx));
582 ASSERT_EQ(0, when_acquired_lock(ictx));
583
584 // get current commit position
585 int64_t initial_tag;
586 int64_t initial_entry;
587 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
588
589 // inject snapshot ops into journal
590 std::string new_image_name(get_temp_image_name());
591 inject_into_journal(ictx, librbd::journal::RenameEvent(1, new_image_name));
592 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
593 close_image(ictx);
594
595 // replay journal
596 ASSERT_EQ(0, open_image(m_image_name, &ictx));
597 ASSERT_EQ(0, when_acquired_lock(ictx));
598
599 int64_t current_tag;
600 int64_t current_entry;
601 get_journal_commit_position(ictx, &current_tag, &current_entry);
602 ASSERT_EQ(initial_tag + 1, current_tag);
603 ASSERT_EQ(1, current_entry);
604
605 // verify lock ordering constraints
606 librbd::RBD rbd;
607 ASSERT_EQ(0, rbd.rename(m_ioctx, new_image_name.c_str(), m_image_name.c_str()));
608 }
609
610 TEST_F(TestJournalReplay, Resize) {
611 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
612
613 librbd::ImageCtx *ictx;
614
615 ASSERT_EQ(0, open_image(m_image_name, &ictx));
616 ASSERT_EQ(0, when_acquired_lock(ictx));
617
618 // get current commit position
619 int64_t initial_tag;
620 int64_t initial_entry;
621 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
622
623 // inject snapshot ops into journal
624 inject_into_journal(ictx, librbd::journal::ResizeEvent(1, 16));
625 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
626 close_image(ictx);
627
628 // replay journal
629 ASSERT_EQ(0, open_image(m_image_name, &ictx));
630 ASSERT_EQ(0, when_acquired_lock(ictx));
631
632 int64_t current_tag;
633 int64_t current_entry;
634 get_journal_commit_position(ictx, &current_tag, &current_entry);
635 ASSERT_EQ(initial_tag + 1, current_tag);
636 ASSERT_EQ(1, current_entry);
637
638 // verify lock ordering constraints
639 librbd::NoOpProgressContext no_op_progress;
640 ASSERT_EQ(0, ictx->operations->resize(0, true, no_op_progress));
641 }
642
643 TEST_F(TestJournalReplay, Flatten) {
644 REQUIRE_FEATURE(RBD_FEATURE_LAYERING | RBD_FEATURE_JOURNALING);
645
646 librbd::ImageCtx *ictx;
647 ASSERT_EQ(0, open_image(m_image_name, &ictx));
648 ASSERT_EQ(0, ictx->operations->snap_create(cls::rbd::UserSnapshotNamespace(),
649 "snap"));
650 ASSERT_EQ(0, ictx->operations->snap_protect(cls::rbd::UserSnapshotNamespace(),
651 "snap"));
652
653 std::string clone_name = get_temp_image_name();
654 int order = ictx->order;
655 ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap", m_ioctx,
656 clone_name.c_str(), ictx->features, &order, 0, 0));
657
658 librbd::ImageCtx *ictx2;
659 ASSERT_EQ(0, open_image(clone_name, &ictx2));
660 ASSERT_EQ(0, when_acquired_lock(ictx2));
661
662 // get current commit position
663 int64_t initial_tag;
664 int64_t initial_entry;
665 get_journal_commit_position(ictx2, &initial_tag, &initial_entry);
666
667 // inject snapshot ops into journal
668 inject_into_journal(ictx2, librbd::journal::FlattenEvent(1));
669 inject_into_journal(ictx2, librbd::journal::OpFinishEvent(1, 0));
670 close_image(ictx2);
671
672 // replay journal
673 ASSERT_EQ(0, open_image(clone_name, &ictx2));
674 ASSERT_EQ(0, when_acquired_lock(ictx2));
675
676 int64_t current_tag;
677 int64_t current_entry;
678 get_journal_commit_position(ictx2, &current_tag, &current_entry);
679 ASSERT_EQ(initial_tag + 1, current_tag);
680 ASSERT_EQ(1, current_entry);
681 ASSERT_EQ(0, ictx->operations->snap_unprotect(cls::rbd::UserSnapshotNamespace(),
682 "snap"));
683
684 // verify lock ordering constraints
685 librbd::NoOpProgressContext no_op;
686 ASSERT_EQ(-EINVAL, ictx2->operations->flatten(no_op));
687 }
688
689 TEST_F(TestJournalReplay, UpdateFeatures) {
690 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
691
692 librbd::ImageCtx *ictx;
693
694 ASSERT_EQ(0, open_image(m_image_name, &ictx));
695 ASSERT_EQ(0, when_acquired_lock(ictx));
696
697 uint64_t features = RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF;
698 bool enabled = !ictx->test_features(features);
699
700 // get current commit position
701 int64_t initial_tag;
702 int64_t initial_entry;
703 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
704
705 // inject update_features op into journal
706 inject_into_journal(ictx, librbd::journal::UpdateFeaturesEvent(1, features,
707 enabled));
708 close_image(ictx);
709
710 // replay journal
711 ASSERT_EQ(0, open_image(m_image_name, &ictx));
712 ASSERT_EQ(0, when_acquired_lock(ictx));
713
714 int64_t current_tag;
715 int64_t current_entry;
716 get_journal_commit_position(ictx, &current_tag, &current_entry);
717 ASSERT_EQ(initial_tag + 1, current_tag);
718 ASSERT_EQ(0, current_entry);
719
720 ASSERT_EQ(enabled, ictx->test_features(features));
721
722 // verify lock ordering constraints
723 ASSERT_EQ(0, ictx->operations->update_features(features, !enabled));
724 }
725
726 TEST_F(TestJournalReplay, MetadataSet) {
727 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
728
729 librbd::ImageCtx *ictx;
730
731 ASSERT_EQ(0, open_image(m_image_name, &ictx));
732 ASSERT_EQ(0, when_acquired_lock(ictx));
733
734 // get current commit position
735 int64_t initial_tag;
736 int64_t initial_entry;
737 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
738
739 // inject metadata_set op into journal
740 inject_into_journal(ictx, librbd::journal::MetadataSetEvent(1, "key", "value"));
741 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
742 close_image(ictx);
743
744 // replay journal
745 ASSERT_EQ(0, open_image(m_image_name, &ictx));
746 ASSERT_EQ(0, when_acquired_lock(ictx));
747
748 int64_t current_tag;
749 int64_t current_entry;
750 get_journal_commit_position(ictx, &current_tag, &current_entry);
751 ASSERT_EQ(initial_tag + 1, current_tag);
752 ASSERT_EQ(1, current_entry);
753
754 std::string value;
755 ASSERT_EQ(0, librbd::metadata_get(ictx, "key", &value));
756 ASSERT_EQ("value", value);
757
758 // verify lock ordering constraints
759 ASSERT_EQ(0, ictx->operations->metadata_set("key2", "value"));
760 }
761
762 TEST_F(TestJournalReplay, MetadataRemove) {
763 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
764
765 librbd::ImageCtx *ictx;
766
767 ASSERT_EQ(0, open_image(m_image_name, &ictx));
768 ASSERT_EQ(0, when_acquired_lock(ictx));
769
770 ASSERT_EQ(0, ictx->operations->metadata_set("key", "value"));
771
772 // get current commit position
773 int64_t initial_tag;
774 int64_t initial_entry;
775 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
776
777 // inject metadata_remove op into journal
778 inject_into_journal(ictx, librbd::journal::MetadataRemoveEvent(1, "key"));
779 inject_into_journal(ictx, librbd::journal::OpFinishEvent(1, 0));
780 close_image(ictx);
781
782 // replay journal
783 ASSERT_EQ(0, open_image(m_image_name, &ictx));
784 ASSERT_EQ(0, when_acquired_lock(ictx));
785
786 int64_t current_tag;
787 int64_t current_entry;
788 get_journal_commit_position(ictx, &current_tag, &current_entry);
789 ASSERT_EQ(initial_tag, current_tag);
790 ASSERT_EQ(initial_entry + 2, current_entry);
791
792 std::string value;
793 ASSERT_EQ(-ENOENT, librbd::metadata_get(ictx, "key", &value));
794
795 // verify lock ordering constraints
796 ASSERT_EQ(0, ictx->operations->metadata_set("key", "value"));
797 ASSERT_EQ(0, ictx->operations->metadata_remove("key"));
798 }
799
800 TEST_F(TestJournalReplay, ObjectPosition) {
801 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
802
803 librbd::ImageCtx *ictx;
804 ASSERT_EQ(0, open_image(m_image_name, &ictx));
805 ASSERT_EQ(0, when_acquired_lock(ictx));
806
807 // get current commit position
808 int64_t initial_tag;
809 int64_t initial_entry;
810 get_journal_commit_position(ictx, &initial_tag, &initial_entry);
811
812 std::string payload(4096, '1');
813 bufferlist payload_bl;
814 payload_bl.append(payload);
815 auto aio_comp = new librbd::io::AioCompletion();
816 ictx->io_work_queue->aio_write(aio_comp, 0, payload.size(),
817 bufferlist{payload_bl}, 0);
818 ASSERT_EQ(0, aio_comp->wait_for_complete());
819 aio_comp->release();
820
821 aio_comp = new librbd::io::AioCompletion();
822 ictx->io_work_queue->aio_flush(aio_comp);
823 ASSERT_EQ(0, aio_comp->wait_for_complete());
824 aio_comp->release();
825
826 // check the commit position updated
827 int64_t current_tag;
828 int64_t current_entry;
829 get_journal_commit_position(ictx, &current_tag, &current_entry);
830 ASSERT_EQ(initial_tag + 1, current_tag);
831 ASSERT_EQ(1, current_entry);
832
833 // write again
834
835 aio_comp = new librbd::io::AioCompletion();
836 ictx->io_work_queue->aio_write(aio_comp, 0, payload.size(),
837 bufferlist{payload_bl}, 0);
838 ASSERT_EQ(0, aio_comp->wait_for_complete());
839 aio_comp->release();
840
841 aio_comp = new librbd::io::AioCompletion();
842 ictx->io_work_queue->aio_flush(aio_comp);
843 ASSERT_EQ(0, aio_comp->wait_for_complete());
844 aio_comp->release();
845
846 {
847 // user flush requests are ignored when journaling + cache are enabled
848 RWLock::RLocker owner_lock(ictx->owner_lock);
849 ictx->flush();
850 }
851
852 // check the commit position updated
853 get_journal_commit_position(ictx, &current_tag, &current_entry);
854 ASSERT_EQ(initial_tag + 1, current_tag);
855 ASSERT_EQ(3, current_entry);
856 }