]>
Commit | Line | Data |
---|---|---|
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 | ||
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> | |
31f18b77 | 34 | PreReleaseRequest<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 | ||
41 | template <typename I> | |
f67539c2 TL |
42 | PreReleaseRequest<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 | ||
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() { | |
7c673cae FG |
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 | ||
11fdf7f2 | 80 | ceph_assert(r == 0); |
7c673cae | 81 | |
f67539c2 | 82 | send_set_require_lock(); |
7c673cae FG |
83 | } |
84 | ||
85 | template <typename I> | |
f67539c2 TL |
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 | ||
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 | ||
112 | template <typename I> | |
f67539c2 | 113 | void 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 | ||
125 | template <typename I> | |
126 | void 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 | ||
135 | template <typename I> | |
136 | void 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 | ||
143 | template <typename I> | |
144 | void 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 | ||
159 | template <typename I> | |
160 | void 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 | ||
167 | template <typename I> | |
168 | void 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 | ||
179 | template <typename I> | |
180 | void 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 | ||
196 | template <typename I> | |
11fdf7f2 | 197 | void 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 | ||
207 | template <typename I> | |
208 | void 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 | ||
224 | template <typename I> | |
225 | void 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 | ||
242 | template <typename I> | |
243 | void 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 | ||
254 | template <typename I> | |
255 | void 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 | ||
265 | template <typename I> | |
266 | void 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 | ||
274 | template <typename I> | |
275 | void 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 | ||
295 | template <typename I> | |
296 | void 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 | ||
311 | template <typename I> | |
312 | void 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 | ||
332 | template <typename I> | |
333 | void 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 | ||
345 | template <typename I> | |
346 | void PreReleaseRequest<I>::send_unlock() { | |
347 | CephContext *cct = m_image_ctx.cct; | |
348 | ldout(cct, 10) << dendl; | |
349 | ||
350 | finish(); | |
351 | } | |
352 | ||
353 | template <typename I> | |
354 | void PreReleaseRequest<I>::finish() { | |
355 | m_on_finish->complete(m_error_result); | |
356 | delete this; | |
357 | } | |
358 | ||
359 | } // namespace exclusive_lock | |
360 | } // namespace librbd | |
361 | ||
362 | template class librbd::exclusive_lock::PreReleaseRequest<librbd::ImageCtx>; |