]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/exclusive_lock/PreReleaseRequest.cc
update sources to v12.1.1
[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"
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
21namespace librbd {
22namespace exclusive_lock {
23
24using util::create_async_context_callback;
25using util::create_context_callback;
26
27template <typename I>
31f18b77
FG
28PreReleaseRequest<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);
7c673cae
FG
33}
34
35template <typename I>
36PreReleaseRequest<I>::PreReleaseRequest(I &image_ctx, bool shutting_down,
31f18b77 37 AsyncOpTracker &async_op_tracker,
7c673cae 38 Context *on_finish)
31f18b77
FG
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)) {
7c673cae
FG
42}
43
44template <typename I>
45PreReleaseRequest<I>::~PreReleaseRequest() {
46 if (!m_shutting_down) {
47 m_image_ctx.state->handle_prepare_lock_complete();
48 }
49}
50
51template <typename I>
52void PreReleaseRequest<I>::send() {
53 send_prepare_lock();
54}
55
56template <typename I>
57void 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
72template <typename I>
73void 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
80template <typename I>
81void 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
91template <typename I>
92void 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
101template <typename I>
102void 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);
224ce89b
WB
112 // setting the lock as required will automatically cause the IO
113 // queue to re-request the lock if any IO is queued
114 if (m_image_ctx.clone_copy_on_read ||
115 m_image_ctx.test_features(RBD_FEATURE_JOURNALING)) {
116 m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_BOTH, true);
117 } else {
118 m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_WRITE, true);
7c673cae
FG
119 }
120 m_image_ctx.io_work_queue->block_writes(ctx);
121 }
122}
123
124template <typename I>
125void PreReleaseRequest<I>::handle_block_writes(int r) {
126 CephContext *cct = m_image_ctx.cct;
127 ldout(cct, 10) << "r=" << r << dendl;
128
129 if (r == -EBLACKLISTED) {
130 // allow clean shut down if blacklisted
131 lderr(cct) << "failed to block writes because client is blacklisted"
132 << dendl;
133 } else if (r < 0) {
134 lderr(cct) << "failed to block writes: " << cpp_strerror(r) << dendl;
135 m_image_ctx.io_work_queue->unblock_writes();
136 save_result(r);
137 finish();
138 return;
139 }
140
31f18b77
FG
141 send_wait_for_ops();
142}
143
144template <typename I>
145void PreReleaseRequest<I>::send_wait_for_ops() {
146 CephContext *cct = m_image_ctx.cct;
147 ldout(cct, 10) << dendl;
148
149 Context *ctx = create_context_callback<
150 PreReleaseRequest<I>, &PreReleaseRequest<I>::handle_wait_for_ops>(this);
151 m_async_op_tracker.wait_for_ops(ctx);
152}
153
154template <typename I>
155void PreReleaseRequest<I>::handle_wait_for_ops(int r) {
156 CephContext *cct = m_image_ctx.cct;
157 ldout(cct, 10) << dendl;
158
7c673cae
FG
159 send_invalidate_cache(false);
160}
161
162template <typename I>
163void PreReleaseRequest<I>::send_invalidate_cache(bool purge_on_error) {
164 if (m_image_ctx.object_cacher == nullptr) {
165 send_flush_notifies();
166 return;
167 }
168
169 CephContext *cct = m_image_ctx.cct;
170 ldout(cct, 10) << "purge_on_error=" << purge_on_error << dendl;
171
172 RWLock::RLocker owner_lock(m_image_ctx.owner_lock);
173 Context *ctx = create_async_context_callback(
174 m_image_ctx, create_context_callback<
175 PreReleaseRequest<I>,
176 &PreReleaseRequest<I>::handle_invalidate_cache>(this));
177 m_image_ctx.invalidate_cache(purge_on_error, ctx);
178}
179
180template <typename I>
181void PreReleaseRequest<I>::handle_invalidate_cache(int r) {
182 CephContext *cct = m_image_ctx.cct;
183 ldout(cct, 10) << "r=" << r << dendl;
184
185 if (r == -EBLACKLISTED) {
186 lderr(cct) << "failed to invalidate cache because client is blacklisted"
187 << dendl;
188 if (!m_image_ctx.is_cache_empty()) {
189 // force purge the cache after after being blacklisted
190 send_invalidate_cache(true);
191 return;
192 }
193 } else if (r < 0 && r != -EBUSY) {
194 lderr(cct) << "failed to invalidate cache: " << cpp_strerror(r)
195 << dendl;
196 m_image_ctx.io_work_queue->unblock_writes();
197 save_result(r);
198 finish();
199 return;
200 }
201
202 send_flush_notifies();
203}
204
205template <typename I>
206void PreReleaseRequest<I>::send_flush_notifies() {
207 CephContext *cct = m_image_ctx.cct;
208 ldout(cct, 10) << dendl;
209
210 using klass = PreReleaseRequest<I>;
211 Context *ctx =
212 create_context_callback<klass, &klass::handle_flush_notifies>(this);
213 m_image_ctx.image_watcher->flush(ctx);
214}
215
216template <typename I>
217void PreReleaseRequest<I>::handle_flush_notifies(int r) {
218 CephContext *cct = m_image_ctx.cct;
219 ldout(cct, 10) << dendl;
220
221 assert(r == 0);
222 send_close_journal();
223}
224
225template <typename I>
226void PreReleaseRequest<I>::send_close_journal() {
227 {
228 RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
229 std::swap(m_journal, m_image_ctx.journal);
230 }
231
232 if (m_journal == nullptr) {
233 send_close_object_map();
234 return;
235 }
236
237 CephContext *cct = m_image_ctx.cct;
238 ldout(cct, 10) << dendl;
239
240 using klass = PreReleaseRequest<I>;
241 Context *ctx = create_context_callback<klass, &klass::handle_close_journal>(
242 this);
243 m_journal->close(ctx);
244}
245
246template <typename I>
247void PreReleaseRequest<I>::handle_close_journal(int r) {
248 CephContext *cct = m_image_ctx.cct;
249 ldout(cct, 10) << "r=" << r << dendl;
250
251 if (r < 0) {
252 // error implies some journal events were not flushed -- continue
253 lderr(cct) << "failed to close journal: " << cpp_strerror(r) << dendl;
254 }
255
256 delete m_journal;
257
258 send_close_object_map();
259}
260
261template <typename I>
262void PreReleaseRequest<I>::send_close_object_map() {
263 {
264 RWLock::WLocker snap_locker(m_image_ctx.snap_lock);
265 std::swap(m_object_map, m_image_ctx.object_map);
266 }
267
268 if (m_object_map == nullptr) {
269 send_unlock();
270 return;
271 }
272
273 CephContext *cct = m_image_ctx.cct;
274 ldout(cct, 10) << dendl;
275
276 using klass = PreReleaseRequest<I>;
277 Context *ctx = create_context_callback<
278 klass, &klass::handle_close_object_map>(this);
279 m_object_map->close(ctx);
280}
281
282template <typename I>
283void PreReleaseRequest<I>::handle_close_object_map(int r) {
284 CephContext *cct = m_image_ctx.cct;
285 ldout(cct, 10) << "r=" << r << dendl;
286
287 // object map shouldn't return errors
288 assert(r == 0);
289 delete m_object_map;
290
291 send_unlock();
292}
293
294template <typename I>
295void PreReleaseRequest<I>::send_unlock() {
296 CephContext *cct = m_image_ctx.cct;
297 ldout(cct, 10) << dendl;
298
299 finish();
300}
301
302template <typename I>
303void PreReleaseRequest<I>::finish() {
304 m_on_finish->complete(m_error_result);
305 delete this;
306}
307
308} // namespace exclusive_lock
309} // namespace librbd
310
311template class librbd::exclusive_lock::PreReleaseRequest<librbd::ImageCtx>;