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