Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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(),
147                                                        ictx->skip_partial_discard));
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();
159   if (ictx->skip_partial_discard) {
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,
174                       librbd::journal::AioDiscardEvent(0, payload.size(),
175                                                        ictx->skip_partial_discard));
176   inject_into_journal(ictx,
177                       librbd::journal::AioDiscardEvent(0, payload.size(),
178                                                        ictx->skip_partial_discard));
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();
189   ictx->io_work_queue->aio_discard(aio_comp, 0, read_payload.size(),
190                                    ictx->skip_partial_discard);
191   ASSERT_EQ(0, aio_comp->wait_for_complete());
192   aio_comp->release();
193 }
194
195 TEST_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
256 TEST_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
302 TEST_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
342 TEST_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
387 TEST_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
442 TEST_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
491 TEST_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
532 TEST_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
580 TEST_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
614 TEST_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
647 TEST_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
693 TEST_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
730 TEST_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
766 TEST_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
804 TEST_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 }