Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / exclusive_lock / PreReleaseRequest.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/exclusive_lock/PreReleaseRequest.h"
5 #include "common/AsyncOpTracker.h"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "librbd/ExclusiveLock.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/ImageWatcher.h"
11 #include "librbd/Journal.h"
12 #include "librbd/ObjectMap.h"
13 #include "librbd/Utils.h"
14 #include "librbd/io/ImageRequestWQ.h"
15
16 #define dout_subsys ceph_subsys_rbd
17 #undef dout_prefix
18 #define dout_prefix *_dout << "librbd::exclusive_lock::PreReleaseRequest: " \
19                            << this << " " << __func__ << ": "
20
21 namespace librbd {
22 namespace exclusive_lock {
23
24 using util::create_async_context_callback;
25 using util::create_context_callback;
26
27 template <typename I>
28 PreReleaseRequest<I>* PreReleaseRequest<I>::create(
29     I &image_ctx, bool shutting_down, AsyncOpTracker &async_op_tracker,
30     Context *on_finish) {
31   return new PreReleaseRequest(image_ctx, shutting_down, async_op_tracker,
32                                on_finish);
33 }
34
35 template <typename I>
36 PreReleaseRequest<I>::PreReleaseRequest(I &image_ctx, bool shutting_down,
37                                         AsyncOpTracker &async_op_tracker,
38                                         Context *on_finish)
39   : m_image_ctx(image_ctx), m_shutting_down(shutting_down),
40     m_async_op_tracker(async_op_tracker),
41     m_on_finish(create_async_context_callback(image_ctx, on_finish)) {
42 }
43
44 template <typename I>
45 PreReleaseRequest<I>::~PreReleaseRequest() {
46   if (!m_shutting_down) {
47     m_image_ctx.state->handle_prepare_lock_complete();
48   }
49 }
50
51 template <typename I>
52 void PreReleaseRequest<I>::send() {
53   send_prepare_lock();
54 }
55
56 template <typename I>
57 void PreReleaseRequest<I>::send_prepare_lock() {
58   if (m_shutting_down) {
59     send_cancel_op_requests();
60     return;
61   }
62
63   CephContext *cct = m_image_ctx.cct;
64   ldout(cct, 10) << dendl;
65
66   // release the lock if the image is not busy performing other actions
67   Context *ctx = create_context_callback<
68     PreReleaseRequest<I>, &PreReleaseRequest<I>::handle_prepare_lock>(this);
69   m_image_ctx.state->prepare_lock(ctx);
70 }
71
72 template <typename I>
73 void PreReleaseRequest<I>::handle_prepare_lock(int r) {
74   CephContext *cct = m_image_ctx.cct;
75   ldout(cct, 10) << "r=" << r << dendl;
76
77   send_cancel_op_requests();
78 }
79
80 template <typename I>
81 void PreReleaseRequest<I>::send_cancel_op_requests() {
82   CephContext *cct = m_image_ctx.cct;
83   ldout(cct, 10) << dendl;
84
85   using klass = PreReleaseRequest<I>;
86   Context *ctx = create_context_callback<
87     klass, &klass::handle_cancel_op_requests>(this);
88   m_image_ctx.cancel_async_requests(ctx);
89 }
90
91 template <typename I>
92 void PreReleaseRequest<I>::handle_cancel_op_requests(int r) {
93   CephContext *cct = m_image_ctx.cct;
94   ldout(cct, 10) << "r=" << r << dendl;
95
96   assert(r == 0);
97
98   send_block_writes();
99 }
100
101 template <typename I>
102 void PreReleaseRequest<I>::send_block_writes() {
103   CephContext *cct = m_image_ctx.cct;
104   ldout(cct, 10) << dendl;
105
106   using klass = PreReleaseRequest<I>;
107   Context *ctx = create_context_callback<
108     klass, &klass::handle_block_writes>(this);
109
110   {
111     RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
112     // setting the lock as required will automatically cause the IO
113     // queue to re-request the lock if any IO is queued
114     if (m_image_ctx.clone_copy_on_read ||
115         m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
116       m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_BOTH, true);
117     } else {
118       m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_WRITE, true);
119     }
120     m_image_ctx.io_work_queue->block_writes(ctx);
121   }
122 }
123
124 template <typename I>
125 void PreReleaseRequest<I>::handle_block_writes(int r) {
126   CephContext *cct = m_image_ctx.cct;
127   ldout(cct, 10) << "r=" << r << dendl;
128
129   if (r == -EBLACKLISTED) {
130     // allow clean shut down if blacklisted
131     lderr(cct) << "failed to block writes because client is blacklisted"
132                << dendl;
133   } else if (r < 0) {
134     lderr(cct) << "failed to block writes: " << cpp_strerror(r) << dendl;
135     m_image_ctx.io_work_queue->unblock_writes();
136     save_result(r);
137     finish();
138     return;
139   }
140
141   send_wait_for_ops();
142 }
143
144 template <typename I>
145 void PreReleaseRequest<I>::send_wait_for_ops() {
146   CephContext *cct = m_image_ctx.cct;
147   ldout(cct, 10) << dendl;
148
149   Context *ctx = create_context_callback<
150     PreReleaseRequest<I>, &PreReleaseRequest<I>::handle_wait_for_ops>(this);
151   m_async_op_tracker.wait_for_ops(ctx);
152 }
153
154 template <typename I>
155 void PreReleaseRequest<I>::handle_wait_for_ops(int r) {
156   CephContext *cct = m_image_ctx.cct;
157   ldout(cct, 10) << dendl;
158
159   send_invalidate_cache(false);
160 }
161
162 template <typename I>
163 void PreReleaseRequest<I>::send_invalidate_cache(bool purge_on_error) {
164   if (m_image_ctx.object_cacher == nullptr) {
165     send_flush_notifies();
166     return;
167   }
168
169   CephContext *cct = m_image_ctx.cct;
170   ldout(cct, 10) << "purge_on_error=" << purge_on_error << dendl;
171
172   RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
173   Context *ctx = create_async_context_callback(
174     m_image_ctx, create_context_callback<
175       PreReleaseRequest<I>,
176       &PreReleaseRequest<I>::handle_invalidate_cache>(this));
177   m_image_ctx.invalidate_cache(purge_on_error, ctx);
178 }
179
180 template <typename I>
181 void PreReleaseRequest<I>::handle_invalidate_cache(int r) {
182   CephContext *cct = m_image_ctx.cct;
183   ldout(cct, 10) << "r=" << r << dendl;
184
185   if (r == -EBLACKLISTED) {
186     lderr(cct) << "failed to invalidate cache because client is blacklisted"
187                << dendl;
188     if (!m_image_ctx.is_cache_empty()) {
189       // force purge the cache after after being blacklisted
190       send_invalidate_cache(true);
191       return;
192     }
193   } else if (r < 0 && r != -EBUSY) {
194     lderr(cct) << "failed to invalidate cache: " << cpp_strerror(r)
195                << dendl;
196     m_image_ctx.io_work_queue->unblock_writes();
197     save_result(r);
198     finish();
199     return;
200   }
201
202   send_flush_notifies();
203 }
204
205 template <typename I>
206 void PreReleaseRequest<I>::send_flush_notifies() {
207   CephContext *cct = m_image_ctx.cct;
208   ldout(cct, 10) << dendl;
209
210   using klass = PreReleaseRequest<I>;
211   Context *ctx =
212     create_context_callback<klass, &klass::handle_flush_notifies>(this);
213   m_image_ctx.image_watcher->flush(ctx);
214 }
215
216 template <typename I>
217 void PreReleaseRequest<I>::handle_flush_notifies(int r) {
218   CephContext *cct = m_image_ctx.cct;
219   ldout(cct, 10) << dendl;
220
221   assert(r == 0);
222   send_close_journal();
223 }
224
225 template <typename I>
226 void PreReleaseRequest<I>::send_close_journal() {
227   {
228     RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
229     std::swap(m_journal, m_image_ctx.journal);
230   }
231
232   if (m_journal == nullptr) {
233     send_close_object_map();
234     return;
235   }
236
237   CephContext *cct = m_image_ctx.cct;
238   ldout(cct, 10) << dendl;
239
240   using klass = PreReleaseRequest<I>;
241   Context *ctx = create_context_callback<klass, &klass::handle_close_journal>(
242     this);
243   m_journal->close(ctx);
244 }
245
246 template <typename I>
247 void PreReleaseRequest<I>::handle_close_journal(int r) {
248   CephContext *cct = m_image_ctx.cct;
249   ldout(cct, 10) << "r=" << r << dendl;
250
251   if (r < 0) {
252     // error implies some journal events were not flushed -- continue
253     lderr(cct) << "failed to close journal: " << cpp_strerror(r) << dendl;
254   }
255
256   delete m_journal;
257
258   send_close_object_map();
259 }
260
261 template <typename I>
262 void PreReleaseRequest<I>::send_close_object_map() {
263   {
264     RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
265     std::swap(m_object_map, m_image_ctx.object_map);
266   }
267
268   if (m_object_map == nullptr) {
269     send_unlock();
270     return;
271   }
272
273   CephContext *cct = m_image_ctx.cct;
274   ldout(cct, 10) << dendl;
275
276   using klass = PreReleaseRequest<I>;
277   Context *ctx = create_context_callback<
278     klass, &klass::handle_close_object_map>(this);
279   m_object_map->close(ctx);
280 }
281
282 template <typename I>
283 void PreReleaseRequest<I>::handle_close_object_map(int r) {
284   CephContext *cct = m_image_ctx.cct;
285   ldout(cct, 10) << "r=" << r << dendl;
286
287   // object map shouldn't return errors
288   assert(r == 0);
289   delete m_object_map;
290
291   send_unlock();
292 }
293
294 template <typename I>
295 void PreReleaseRequest<I>::send_unlock() {
296   CephContext *cct = m_image_ctx.cct;
297   ldout(cct, 10) << dendl;
298
299   finish();
300 }
301
302 template <typename I>
303 void PreReleaseRequest<I>::finish() {
304   m_on_finish->complete(m_error_result);
305   delete this;
306 }
307
308 } // namespace exclusive_lock
309 } // namespace librbd
310
311 template class librbd::exclusive_lock::PreReleaseRequest<librbd::ImageCtx>;