Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / operation / Request.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 "librbd/operation/Request.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "common/WorkQueue.h"
8 #include "librbd/ImageCtx.h"
9
10 #define dout_subsys ceph_subsys_rbd
11 #undef dout_prefix
12 #define dout_prefix *_dout << "librbd::Request: "
13
14 namespace librbd {
15 namespace operation {
16
17 template <typename I>
18 Request<I>::Request(I &image_ctx, Context *on_finish, uint64_t journal_op_tid)
19   : AsyncRequest<I>(image_ctx, on_finish), m_op_tid(journal_op_tid) {
20 }
21
22 template <typename I>
23 void Request<I>::send() {
24   I &image_ctx = this->m_image_ctx;
25   assert(image_ctx.owner_lock.is_locked());
26
27   // automatically create the event if we don't need to worry
28   // about affecting concurrent IO ops
29   if (can_affect_io() || !append_op_event()) {
30     send_op();
31   }
32 }
33
34 template <typename I>
35 Context *Request<I>::create_context_finisher(int r) {
36   // automatically commit the event if required (delete after commit)
37   if (m_appended_op_event && !m_committed_op_event &&
38       commit_op_event(r)) {
39     return nullptr;
40   }
41
42   I &image_ctx = this->m_image_ctx;
43   CephContext *cct = image_ctx.cct;
44   ldout(cct, 10) << this << " " << __func__ << dendl;
45   return util::create_context_callback<Request<I>, &Request<I>::finish>(this);
46 }
47
48 template <typename I>
49 void Request<I>::finish_and_destroy(int r) {
50   I &image_ctx = this->m_image_ctx;
51   CephContext *cct = image_ctx.cct;
52   ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
53
54   // automatically commit the event if required (delete after commit)
55   if (m_appended_op_event && !m_committed_op_event &&
56       commit_op_event(r)) {
57     return;
58   }
59
60   AsyncRequest<I>::finish_and_destroy(r);
61 }
62
63 template <typename I>
64 void Request<I>::finish(int r) {
65   I &image_ctx = this->m_image_ctx;
66   CephContext *cct = image_ctx.cct;
67   ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
68
69   assert(!m_appended_op_event || m_committed_op_event);
70   AsyncRequest<I>::finish(r);
71 }
72
73 template <typename I>
74 bool Request<I>::append_op_event() {
75   I &image_ctx = this->m_image_ctx;
76
77   assert(image_ctx.owner_lock.is_locked());
78   RWLock::RLocker snap_locker(image_ctx.snap_lock);
79   if (image_ctx.journal != nullptr &&
80       image_ctx.journal->is_journal_appending()) {
81     append_op_event(util::create_context_callback<
82       Request<I>, &Request<I>::handle_op_event_safe>(this));
83     return true;
84   }
85   return false;
86 }
87
88 template <typename I>
89 bool Request<I>::commit_op_event(int r) {
90   I &image_ctx = this->m_image_ctx;
91   RWLock::RLocker snap_locker(image_ctx.snap_lock);
92
93   if (!m_appended_op_event) {
94     return false;
95   }
96
97   assert(m_op_tid != 0);
98   assert(!m_committed_op_event);
99   m_committed_op_event = true;
100
101   if (image_ctx.journal != nullptr &&
102       image_ctx.journal->is_journal_appending()) {
103     CephContext *cct = image_ctx.cct;
104     ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
105
106     // ops will be canceled / completed before closing journal
107     assert(image_ctx.journal->is_journal_ready());
108     image_ctx.journal->commit_op_event(m_op_tid, r,
109                                        new C_CommitOpEvent(this, r));
110     return true;
111   }
112   return false;
113 }
114
115 template <typename I>
116 void Request<I>::handle_commit_op_event(int r, int original_ret_val) {
117   I &image_ctx = this->m_image_ctx;
118   CephContext *cct = image_ctx.cct;
119   ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
120
121   if (r < 0) {
122     lderr(cct) << "failed to commit op event to journal: " << cpp_strerror(r)
123                << dendl;
124   }
125   if (original_ret_val < 0) {
126     r = original_ret_val;
127   }
128   finish(r);
129 }
130
131 template <typename I>
132 void Request<I>::replay_op_ready(Context *on_safe) {
133   I &image_ctx = this->m_image_ctx;
134   assert(image_ctx.owner_lock.is_locked());
135   assert(image_ctx.snap_lock.is_locked());
136   assert(m_op_tid != 0);
137
138   m_appended_op_event = true;
139   image_ctx.journal->replay_op_ready(
140     m_op_tid, util::create_async_context_callback(image_ctx, on_safe));
141 }
142
143 template <typename I>
144 void Request<I>::append_op_event(Context *on_safe) {
145   I &image_ctx = this->m_image_ctx;
146   assert(image_ctx.owner_lock.is_locked());
147   assert(image_ctx.snap_lock.is_locked());
148
149   CephContext *cct = image_ctx.cct;
150   ldout(cct, 10) << this << " " << __func__ << dendl;
151
152   m_op_tid = image_ctx.journal->allocate_op_tid();
153   image_ctx.journal->append_op_event(
154     m_op_tid, journal::EventEntry{create_event(m_op_tid)},
155     new C_AppendOpEvent(this, on_safe));
156 }
157
158 template <typename I>
159 void Request<I>::handle_op_event_safe(int r) {
160   I &image_ctx = this->m_image_ctx;
161   CephContext *cct = image_ctx.cct;
162   ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
163
164   if (r < 0) {
165     lderr(cct) << "failed to commit op event to journal: " << cpp_strerror(r)
166                << dendl;
167     this->finish(r);
168     delete this;
169   } else {
170     assert(!can_affect_io());
171
172     // haven't started the request state machine yet
173     RWLock::RLocker owner_locker(image_ctx.owner_lock);
174     send_op();
175   }
176 }
177
178 } // namespace operation
179 } // namespace librbd
180
181 #ifndef TEST_F
182 template class librbd::operation::Request<librbd::ImageCtx>;
183 #endif