]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/exclusive_lock/PreReleaseRequest.cc
import quincy beta 17.1.0
[ceph.git] / 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/exclusive_lock/ImageDispatch.h"
15 #include "librbd/io/AioCompletion.h"
16 #include "librbd/io/ImageDispatchSpec.h"
17 #include "librbd/io/ImageDispatcherInterface.h"
18 #include "librbd/io/ObjectDispatcherInterface.h"
19 #include "librbd/io/Types.h"
20 #include "librbd/PluginRegistry.h"
21
22 #define dout_subsys ceph_subsys_rbd
23 #undef dout_prefix
24 #define dout_prefix *_dout << "librbd::exclusive_lock::PreReleaseRequest: " \
25 << this << " " << __func__ << ": "
26
27 namespace librbd {
28 namespace exclusive_lock {
29
30 using util::create_async_context_callback;
31 using util::create_context_callback;
32
33 template <typename I>
34 PreReleaseRequest<I>* PreReleaseRequest<I>::create(
35 I &image_ctx, ImageDispatch<I>* image_dispatch, bool shutting_down,
36 AsyncOpTracker &async_op_tracker, Context *on_finish) {
37 return new PreReleaseRequest(image_ctx, image_dispatch, shutting_down,
38 async_op_tracker, on_finish);
39 }
40
41 template <typename I>
42 PreReleaseRequest<I>::PreReleaseRequest(I &image_ctx,
43 ImageDispatch<I>* image_dispatch,
44 bool shutting_down,
45 AsyncOpTracker &async_op_tracker,
46 Context *on_finish)
47 : m_image_ctx(image_ctx), m_image_dispatch(image_dispatch),
48 m_shutting_down(shutting_down), m_async_op_tracker(async_op_tracker),
49 m_on_finish(create_async_context_callback(image_ctx, on_finish)) {
50 }
51
52 template <typename I>
53 PreReleaseRequest<I>::~PreReleaseRequest() {
54 if (!m_shutting_down) {
55 m_image_ctx.state->handle_prepare_lock_complete();
56 }
57 }
58
59 template <typename I>
60 void PreReleaseRequest<I>::send() {
61 send_cancel_op_requests();
62 }
63
64 template <typename I>
65 void PreReleaseRequest<I>::send_cancel_op_requests() {
66 CephContext *cct = m_image_ctx.cct;
67 ldout(cct, 10) << dendl;
68
69 using klass = PreReleaseRequest<I>;
70 Context *ctx = create_context_callback<
71 klass, &klass::handle_cancel_op_requests>(this);
72 m_image_ctx.cancel_async_requests(ctx);
73 }
74
75 template <typename I>
76 void PreReleaseRequest<I>::handle_cancel_op_requests(int r) {
77 CephContext *cct = m_image_ctx.cct;
78 ldout(cct, 10) << "r=" << r << dendl;
79
80 ceph_assert(r == 0);
81
82 send_set_require_lock();
83 }
84
85 template <typename I>
86 void PreReleaseRequest<I>::send_set_require_lock() {
87 if (!m_image_ctx.test_features(RBD_FEATURE_EXCLUSIVE_LOCK)) {
88 // exclusive-lock was disabled, no need to block IOs
89 send_wait_for_ops();
90 return;
91 }
92
93 CephContext *cct = m_image_ctx.cct;
94 ldout(cct, 10) << dendl;
95
96 using klass = PreReleaseRequest<I>;
97 Context *ctx = create_context_callback<
98 klass, &klass::handle_set_require_lock>(this);
99
100 // setting the lock as required will automatically cause the IO
101 // queue to re-request the lock if any IO is queued
102 if (m_image_ctx.clone_copy_on_read ||
103 m_image_ctx.test_features(RBD_FEATURE_JOURNALING) ||
104 m_image_ctx.test_features(RBD_FEATURE_DIRTY_CACHE)) {
105 m_image_dispatch->set_require_lock(m_shutting_down,
106 io::DIRECTION_BOTH, ctx);
107 } else {
108 m_image_dispatch->set_require_lock(m_shutting_down,
109 io::DIRECTION_WRITE, ctx);
110 }
111 }
112
113 template <typename I>
114 void PreReleaseRequest<I>::handle_set_require_lock(int r) {
115 CephContext *cct = m_image_ctx.cct;
116 ldout(cct, 10) << "r=" << r << dendl;
117
118 if (r < 0) {
119 // IOs are still flushed regardless of the error
120 lderr(cct) << "failed to set lock: " << cpp_strerror(r) << dendl;
121 }
122
123 send_wait_for_ops();
124 }
125
126 template <typename I>
127 void PreReleaseRequest<I>::send_wait_for_ops() {
128 CephContext *cct = m_image_ctx.cct;
129 ldout(cct, 10) << dendl;
130
131 Context *ctx = create_context_callback<
132 PreReleaseRequest<I>, &PreReleaseRequest<I>::handle_wait_for_ops>(this);
133 m_async_op_tracker.wait_for_ops(ctx);
134 }
135
136 template <typename I>
137 void PreReleaseRequest<I>::handle_wait_for_ops(int r) {
138 CephContext *cct = m_image_ctx.cct;
139 ldout(cct, 10) << dendl;
140
141 send_prepare_lock();
142 }
143
144 template <typename I>
145 void PreReleaseRequest<I>::send_prepare_lock() {
146 if (m_shutting_down) {
147 send_process_plugin_release_lock();
148 return;
149 }
150
151 CephContext *cct = m_image_ctx.cct;
152 ldout(cct, 10) << dendl;
153
154 // release the lock if the image is not busy performing other actions
155 Context *ctx = create_context_callback<
156 PreReleaseRequest<I>, &PreReleaseRequest<I>::handle_prepare_lock>(this);
157 m_image_ctx.state->prepare_lock(ctx);
158 }
159
160 template <typename I>
161 void PreReleaseRequest<I>::handle_prepare_lock(int r) {
162 CephContext *cct = m_image_ctx.cct;
163 ldout(cct, 10) << "r=" << r << dendl;
164
165 send_process_plugin_release_lock();
166 }
167
168 template <typename I>
169 void PreReleaseRequest<I>::send_process_plugin_release_lock() {
170 CephContext *cct = m_image_ctx.cct;
171 ldout(cct, 10) << dendl;
172
173 std::shared_lock owner_lock{m_image_ctx.owner_lock};
174 Context *ctx = create_async_context_callback(m_image_ctx, create_context_callback<
175 PreReleaseRequest<I>,
176 &PreReleaseRequest<I>::handle_process_plugin_release_lock>(this));
177 m_image_ctx.plugin_registry->prerelease_exclusive_lock(ctx);
178 }
179
180 template <typename I>
181 void PreReleaseRequest<I>::handle_process_plugin_release_lock(int r) {
182 CephContext *cct = m_image_ctx.cct;
183 ldout(cct, 10) << "r=" << r << dendl;
184
185 if (r < 0) {
186 lderr(cct) << "failed to handle plugins before releasing lock: "
187 << cpp_strerror(r) << dendl;
188 m_image_dispatch->unset_require_lock(io::DIRECTION_BOTH);
189 save_result(r);
190 finish();
191 return;
192 }
193
194 send_invalidate_cache();
195 }
196
197 template <typename I>
198 void PreReleaseRequest<I>::send_invalidate_cache() {
199 CephContext *cct = m_image_ctx.cct;
200 ldout(cct, 10) << dendl;
201
202 Context *ctx = create_context_callback<
203 PreReleaseRequest<I>,
204 &PreReleaseRequest<I>::handle_invalidate_cache>(this);
205 m_image_ctx.io_image_dispatcher->invalidate_cache(ctx);
206 }
207
208 template <typename I>
209 void PreReleaseRequest<I>::handle_invalidate_cache(int r) {
210 CephContext *cct = m_image_ctx.cct;
211 ldout(cct, 10) << "r=" << r << dendl;
212
213 if (r < 0 && r != -EBLOCKLISTED && r != -EBUSY) {
214 lderr(cct) << "failed to invalidate cache: " << cpp_strerror(r)
215 << dendl;
216 m_image_dispatch->unset_require_lock(io::DIRECTION_BOTH);
217 save_result(r);
218 finish();
219 return;
220 }
221
222 send_flush_io();
223 }
224
225 template <typename I>
226 void PreReleaseRequest<I>::send_flush_io() {
227 CephContext *cct = m_image_ctx.cct;
228 ldout(cct, 10) << dendl;
229
230 // ensure that all in-flight IO is flushed -- skipping the refresh layer
231 // since it should have been flushed when the lock was required and now
232 // refreshes are disabled / interlocked w/ this state machine.
233 auto ctx = create_context_callback<
234 PreReleaseRequest<I>, &PreReleaseRequest<I>::handle_flush_io>(this);
235 auto aio_comp = io::AioCompletion::create_and_start(
236 ctx, util::get_image_ctx(&m_image_ctx), librbd::io::AIO_TYPE_FLUSH);
237 auto req = io::ImageDispatchSpec::create_flush(
238 m_image_ctx, io::IMAGE_DISPATCH_LAYER_EXCLUSIVE_LOCK, aio_comp,
239 io::FLUSH_SOURCE_EXCLUSIVE_LOCK_SKIP_REFRESH, {});
240 req->send();
241 }
242
243 template <typename I>
244 void PreReleaseRequest<I>::handle_flush_io(int r) {
245 CephContext *cct = m_image_ctx.cct;
246 ldout(cct, 10) << "r=" << r << dendl;
247
248 if (r < 0) {
249 lderr(cct) << "failed to flush IO: " << cpp_strerror(r) << dendl;
250 }
251
252 send_flush_notifies();
253 }
254
255 template <typename I>
256 void PreReleaseRequest<I>::send_flush_notifies() {
257 CephContext *cct = m_image_ctx.cct;
258 ldout(cct, 10) << dendl;
259
260 using klass = PreReleaseRequest<I>;
261 Context *ctx =
262 create_context_callback<klass, &klass::handle_flush_notifies>(this);
263 m_image_ctx.image_watcher->flush(ctx);
264 }
265
266 template <typename I>
267 void PreReleaseRequest<I>::handle_flush_notifies(int r) {
268 CephContext *cct = m_image_ctx.cct;
269 ldout(cct, 10) << dendl;
270
271 ceph_assert(r == 0);
272 send_close_journal();
273 }
274
275 template <typename I>
276 void PreReleaseRequest<I>::send_close_journal() {
277 {
278 std::unique_lock image_locker{m_image_ctx.image_lock};
279 std::swap(m_journal, m_image_ctx.journal);
280 }
281
282 if (m_journal == nullptr) {
283 send_close_object_map();
284 return;
285 }
286
287 CephContext *cct = m_image_ctx.cct;
288 ldout(cct, 10) << dendl;
289
290 using klass = PreReleaseRequest<I>;
291 Context *ctx = create_context_callback<klass, &klass::handle_close_journal>(
292 this);
293 m_journal->close(ctx);
294 }
295
296 template <typename I>
297 void PreReleaseRequest<I>::handle_close_journal(int r) {
298 CephContext *cct = m_image_ctx.cct;
299 ldout(cct, 10) << "r=" << r << dendl;
300
301 if (r < 0) {
302 // error implies some journal events were not flushed -- continue
303 lderr(cct) << "failed to close journal: " << cpp_strerror(r) << dendl;
304 }
305
306 m_journal->put();
307 m_journal = nullptr;
308
309 send_close_object_map();
310 }
311
312 template <typename I>
313 void PreReleaseRequest<I>::send_close_object_map() {
314 {
315 std::unique_lock image_locker{m_image_ctx.image_lock};
316 std::swap(m_object_map, m_image_ctx.object_map);
317 }
318
319 if (m_object_map == nullptr) {
320 send_unlock();
321 return;
322 }
323
324 CephContext *cct = m_image_ctx.cct;
325 ldout(cct, 10) << dendl;
326
327 using klass = PreReleaseRequest<I>;
328 Context *ctx = create_context_callback<
329 klass, &klass::handle_close_object_map>(this, m_object_map);
330 m_object_map->close(ctx);
331 }
332
333 template <typename I>
334 void PreReleaseRequest<I>::handle_close_object_map(int r) {
335 CephContext *cct = m_image_ctx.cct;
336 ldout(cct, 10) << "r=" << r << dendl;
337
338 if (r < 0) {
339 lderr(cct) << "failed to close object map: " << cpp_strerror(r) << dendl;
340 }
341 m_object_map->put();
342
343 send_unlock();
344 }
345
346 template <typename I>
347 void PreReleaseRequest<I>::send_unlock() {
348 CephContext *cct = m_image_ctx.cct;
349 ldout(cct, 10) << dendl;
350
351 finish();
352 }
353
354 template <typename I>
355 void PreReleaseRequest<I>::finish() {
356 m_on_finish->complete(m_error_result);
357 delete this;
358 }
359
360 } // namespace exclusive_lock
361 } // namespace librbd
362
363 template class librbd::exclusive_lock::PreReleaseRequest<librbd::ImageCtx>;