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