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