]>
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" | |
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 | ||
20 | namespace librbd { | |
21 | namespace exclusive_lock { | |
22 | ||
23 | using util::create_async_context_callback; | |
24 | using util::create_context_callback; | |
25 | ||
26 | template <typename I> | |
27 | PreReleaseRequest<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 | ||
33 | template <typename I> | |
34 | PreReleaseRequest<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 | ||
42 | template <typename I> | |
43 | PreReleaseRequest<I>::~PreReleaseRequest() { | |
44 | if (!m_shutting_down) { | |
45 | m_image_ctx.state->handle_prepare_lock_complete(); | |
46 | } | |
47 | } | |
48 | ||
49 | template <typename I> | |
50 | void PreReleaseRequest<I>::send() { | |
51 | send_prepare_lock(); | |
52 | } | |
53 | ||
54 | template <typename I> | |
55 | void 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 | ||
70 | template <typename I> | |
71 | void 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 | ||
78 | template <typename I> | |
79 | void 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 | ||
89 | template <typename I> | |
90 | void 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 | ||
99 | template <typename I> | |
100 | void 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 | ||
117 | template <typename I> | |
118 | void 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 | ||
137 | template <typename I> | |
138 | void 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 | ||
155 | template <typename I> | |
156 | void 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 | ||
180 | template <typename I> | |
181 | void 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 | ||
191 | template <typename I> | |
192 | void 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 | ||
200 | template <typename I> | |
201 | void 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 | ||
221 | template <typename I> | |
222 | void 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 | ||
236 | template <typename I> | |
237 | void 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 | ||
257 | template <typename I> | |
258 | void 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 | ||
269 | template <typename I> | |
270 | void PreReleaseRequest<I>::send_unlock() { | |
271 | CephContext *cct = m_image_ctx.cct; | |
272 | ldout(cct, 10) << dendl; | |
273 | ||
274 | finish(); | |
275 | } | |
276 | ||
277 | template <typename I> | |
278 | void PreReleaseRequest<I>::finish() { | |
279 | m_on_finish->complete(m_error_result); | |
280 | delete this; | |
281 | } | |
282 | ||
283 | } // namespace exclusive_lock | |
284 | } // namespace librbd | |
285 | ||
286 | template class librbd::exclusive_lock::PreReleaseRequest<librbd::ImageCtx>; |