]>
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 || | |
20effc67 TL |
103 | m_image_ctx.test_features(RBD_FEATURE_JOURNALING) || |
104 | m_image_ctx.test_features(RBD_FEATURE_DIRTY_CACHE)) { | |
f67539c2 TL |
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); | |
7c673cae FG |
110 | } |
111 | } | |
112 | ||
113 | template <typename I> | |
f67539c2 | 114 | void PreReleaseRequest<I>::handle_set_require_lock(int r) { |
7c673cae FG |
115 | CephContext *cct = m_image_ctx.cct; |
116 | ldout(cct, 10) << "r=" << r << dendl; | |
117 | ||
f67539c2 TL |
118 | if (r < 0) { |
119 | // IOs are still flushed regardless of the error | |
120 | lderr(cct) << "failed to set lock: " << cpp_strerror(r) << dendl; | |
7c673cae FG |
121 | } |
122 | ||
31f18b77 FG |
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 | ||
f67539c2 TL |
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 | ||
11fdf7f2 | 194 | send_invalidate_cache(); |
7c673cae FG |
195 | } |
196 | ||
197 | template <typename I> | |
11fdf7f2 | 198 | void PreReleaseRequest<I>::send_invalidate_cache() { |
7c673cae | 199 | CephContext *cct = m_image_ctx.cct; |
11fdf7f2 | 200 | ldout(cct, 10) << dendl; |
7c673cae | 201 | |
11fdf7f2 | 202 | Context *ctx = create_context_callback< |
7c673cae | 203 | PreReleaseRequest<I>, |
11fdf7f2 | 204 | &PreReleaseRequest<I>::handle_invalidate_cache>(this); |
f67539c2 | 205 | m_image_ctx.io_image_dispatcher->invalidate_cache(ctx); |
7c673cae FG |
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 | ||
f67539c2 | 213 | if (r < 0 && r != -EBLOCKLISTED && r != -EBUSY) { |
7c673cae FG |
214 | lderr(cct) << "failed to invalidate cache: " << cpp_strerror(r) |
215 | << dendl; | |
f67539c2 | 216 | m_image_dispatch->unset_require_lock(io::DIRECTION_BOTH); |
7c673cae FG |
217 | save_result(r); |
218 | finish(); | |
219 | return; | |
220 | } | |
221 | ||
f67539c2 TL |
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 | ||
7c673cae FG |
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 | ||
11fdf7f2 | 271 | ceph_assert(r == 0); |
7c673cae FG |
272 | send_close_journal(); |
273 | } | |
274 | ||
275 | template <typename I> | |
276 | void PreReleaseRequest<I>::send_close_journal() { | |
277 | { | |
9f95a23c | 278 | std::unique_lock image_locker{m_image_ctx.image_lock}; |
7c673cae FG |
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 | ||
9f95a23c TL |
306 | m_journal->put(); |
307 | m_journal = nullptr; | |
7c673cae FG |
308 | |
309 | send_close_object_map(); | |
310 | } | |
311 | ||
312 | template <typename I> | |
313 | void PreReleaseRequest<I>::send_close_object_map() { | |
314 | { | |
9f95a23c | 315 | std::unique_lock image_locker{m_image_ctx.image_lock}; |
7c673cae FG |
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< | |
9f95a23c | 329 | klass, &klass::handle_close_object_map>(this, m_object_map); |
7c673cae FG |
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 | ||
11fdf7f2 TL |
338 | if (r < 0) { |
339 | lderr(cct) << "failed to close object map: " << cpp_strerror(r) << dendl; | |
340 | } | |
9f95a23c | 341 | m_object_map->put(); |
7c673cae FG |
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>; |