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