]>
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/ImageState.h" | |
5 | #include "include/rbd/librbd.hpp" | |
6 | #include "common/dout.h" | |
7 | #include "common/errno.h" | |
8 | #include "common/Cond.h" | |
9 | #include "common/WorkQueue.h" | |
10 | #include "librbd/ImageCtx.h" | |
11 | #include "librbd/Utils.h" | |
12 | #include "librbd/image/CloseRequest.h" | |
13 | #include "librbd/image/OpenRequest.h" | |
14 | #include "librbd/image/RefreshRequest.h" | |
15 | #include "librbd/image/SetSnapRequest.h" | |
16 | ||
17 | #define dout_subsys ceph_subsys_rbd | |
18 | #undef dout_prefix | |
19 | #define dout_prefix *_dout << "librbd::ImageState: " << this << " " | |
20 | ||
21 | namespace librbd { | |
22 | ||
23 | using util::create_async_context_callback; | |
24 | using util::create_context_callback; | |
25 | ||
26 | class ImageUpdateWatchers { | |
27 | public: | |
28 | ||
11fdf7f2 | 29 | explicit ImageUpdateWatchers(CephContext *cct) : m_cct(cct), |
9f95a23c | 30 | m_lock(ceph::make_mutex(util::unique_lock_name("librbd::ImageUpdateWatchers::m_lock", this))) { |
7c673cae FG |
31 | } |
32 | ||
33 | ~ImageUpdateWatchers() { | |
11fdf7f2 TL |
34 | ceph_assert(m_watchers.empty()); |
35 | ceph_assert(m_in_flight.empty()); | |
36 | ceph_assert(m_pending_unregister.empty()); | |
37 | ceph_assert(m_on_shut_down_finish == nullptr); | |
7c673cae FG |
38 | |
39 | destroy_work_queue(); | |
40 | } | |
41 | ||
42 | void flush(Context *on_finish) { | |
43 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << dendl; | |
44 | { | |
9f95a23c | 45 | std::lock_guard locker{m_lock}; |
7c673cae | 46 | if (!m_in_flight.empty()) { |
9f95a23c | 47 | Context *ctx = new LambdaContext( |
7c673cae FG |
48 | [this, on_finish](int r) { |
49 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ | |
50 | << ": completing flush" << dendl; | |
51 | on_finish->complete(r); | |
52 | }); | |
53 | m_work_queue->queue(ctx, 0); | |
54 | return; | |
55 | } | |
56 | } | |
57 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ | |
58 | << ": completing flush" << dendl; | |
59 | on_finish->complete(0); | |
60 | } | |
61 | ||
62 | void shut_down(Context *on_finish) { | |
63 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << dendl; | |
64 | { | |
9f95a23c | 65 | std::lock_guard locker{m_lock}; |
11fdf7f2 | 66 | ceph_assert(m_on_shut_down_finish == nullptr); |
7c673cae FG |
67 | m_watchers.clear(); |
68 | if (!m_in_flight.empty()) { | |
69 | m_on_shut_down_finish = on_finish; | |
70 | return; | |
71 | } | |
72 | } | |
73 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ | |
74 | << ": completing shut down" << dendl; | |
75 | on_finish->complete(0); | |
76 | } | |
77 | ||
78 | void register_watcher(UpdateWatchCtx *watcher, uint64_t *handle) { | |
79 | ldout(m_cct, 20) << __func__ << ": watcher=" << watcher << dendl; | |
80 | ||
9f95a23c | 81 | std::lock_guard locker{m_lock}; |
11fdf7f2 | 82 | ceph_assert(m_on_shut_down_finish == nullptr); |
7c673cae FG |
83 | |
84 | create_work_queue(); | |
85 | ||
86 | *handle = m_next_handle++; | |
87 | m_watchers.insert(std::make_pair(*handle, watcher)); | |
88 | } | |
89 | ||
90 | void unregister_watcher(uint64_t handle, Context *on_finish) { | |
91 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << ": handle=" | |
92 | << handle << dendl; | |
93 | int r = 0; | |
94 | { | |
9f95a23c | 95 | std::lock_guard locker{m_lock}; |
7c673cae FG |
96 | auto it = m_watchers.find(handle); |
97 | if (it == m_watchers.end()) { | |
98 | r = -ENOENT; | |
99 | } else { | |
100 | if (m_in_flight.find(handle) != m_in_flight.end()) { | |
11fdf7f2 | 101 | ceph_assert(m_pending_unregister.find(handle) == m_pending_unregister.end()); |
7c673cae FG |
102 | m_pending_unregister[handle] = on_finish; |
103 | on_finish = nullptr; | |
104 | } | |
105 | m_watchers.erase(it); | |
106 | } | |
107 | } | |
108 | ||
109 | if (on_finish) { | |
110 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ | |
111 | << ": completing unregister" << dendl; | |
112 | on_finish->complete(r); | |
113 | } | |
114 | } | |
115 | ||
116 | void notify() { | |
117 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << dendl; | |
118 | ||
9f95a23c | 119 | std::lock_guard locker{m_lock}; |
7c673cae FG |
120 | for (auto it : m_watchers) { |
121 | send_notify(it.first, it.second); | |
122 | } | |
123 | } | |
124 | ||
125 | void send_notify(uint64_t handle, UpdateWatchCtx *watcher) { | |
9f95a23c | 126 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
127 | |
128 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << ": handle=" | |
129 | << handle << ", watcher=" << watcher << dendl; | |
130 | ||
131 | m_in_flight.insert(handle); | |
132 | ||
9f95a23c | 133 | Context *ctx = new LambdaContext( |
7c673cae FG |
134 | [this, handle, watcher](int r) { |
135 | handle_notify(handle, watcher); | |
136 | }); | |
137 | ||
138 | m_work_queue->queue(ctx, 0); | |
139 | } | |
140 | ||
141 | void handle_notify(uint64_t handle, UpdateWatchCtx *watcher) { | |
142 | ||
143 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << ": handle=" | |
144 | << handle << ", watcher=" << watcher << dendl; | |
145 | ||
146 | watcher->handle_notify(); | |
147 | ||
148 | Context *on_unregister_finish = nullptr; | |
149 | Context *on_shut_down_finish = nullptr; | |
150 | ||
151 | { | |
9f95a23c | 152 | std::lock_guard locker{m_lock}; |
7c673cae FG |
153 | |
154 | auto in_flight_it = m_in_flight.find(handle); | |
11fdf7f2 | 155 | ceph_assert(in_flight_it != m_in_flight.end()); |
7c673cae FG |
156 | m_in_flight.erase(in_flight_it); |
157 | ||
158 | // If there is no more in flight notifications for this watcher | |
159 | // and it is pending unregister, complete it now. | |
160 | if (m_in_flight.find(handle) == m_in_flight.end()) { | |
161 | auto it = m_pending_unregister.find(handle); | |
162 | if (it != m_pending_unregister.end()) { | |
163 | on_unregister_finish = it->second; | |
164 | m_pending_unregister.erase(it); | |
165 | } | |
166 | } | |
167 | ||
168 | if (m_in_flight.empty()) { | |
11fdf7f2 | 169 | ceph_assert(m_pending_unregister.empty()); |
7c673cae FG |
170 | if (m_on_shut_down_finish != nullptr) { |
171 | std::swap(m_on_shut_down_finish, on_shut_down_finish); | |
172 | } | |
173 | } | |
174 | } | |
175 | ||
176 | if (on_unregister_finish != nullptr) { | |
177 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ | |
178 | << ": completing unregister" << dendl; | |
179 | on_unregister_finish->complete(0); | |
180 | } | |
181 | ||
182 | if (on_shut_down_finish != nullptr) { | |
183 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ | |
184 | << ": completing shut down" << dendl; | |
185 | on_shut_down_finish->complete(0); | |
186 | } | |
187 | } | |
188 | ||
189 | private: | |
190 | class ThreadPoolSingleton : public ThreadPool { | |
191 | public: | |
192 | explicit ThreadPoolSingleton(CephContext *cct) | |
193 | : ThreadPool(cct, "librbd::ImageUpdateWatchers::thread_pool", "tp_librbd", | |
194 | 1) { | |
195 | start(); | |
196 | } | |
197 | ~ThreadPoolSingleton() override { | |
198 | stop(); | |
199 | } | |
200 | }; | |
201 | ||
202 | CephContext *m_cct; | |
9f95a23c | 203 | ceph::mutex m_lock; |
7c673cae FG |
204 | ContextWQ *m_work_queue = nullptr; |
205 | std::map<uint64_t, UpdateWatchCtx*> m_watchers; | |
206 | uint64_t m_next_handle = 0; | |
207 | std::multiset<uint64_t> m_in_flight; | |
208 | std::map<uint64_t, Context*> m_pending_unregister; | |
209 | Context *m_on_shut_down_finish = nullptr; | |
210 | ||
211 | void create_work_queue() { | |
212 | if (m_work_queue != nullptr) { | |
213 | return; | |
214 | } | |
11fdf7f2 TL |
215 | auto& thread_pool = m_cct->lookup_or_create_singleton_object< |
216 | ThreadPoolSingleton>("librbd::ImageUpdateWatchers::thread_pool", | |
217 | false, m_cct); | |
7c673cae | 218 | m_work_queue = new ContextWQ("librbd::ImageUpdateWatchers::op_work_queue", |
11fdf7f2 TL |
219 | m_cct->_conf.get_val<uint64_t>("rbd_op_thread_timeout"), |
220 | &thread_pool); | |
7c673cae FG |
221 | } |
222 | ||
223 | void destroy_work_queue() { | |
224 | if (m_work_queue == nullptr) { | |
225 | return; | |
226 | } | |
227 | m_work_queue->drain(); | |
228 | delete m_work_queue; | |
229 | } | |
230 | }; | |
231 | ||
232 | template <typename I> | |
233 | ImageState<I>::ImageState(I *image_ctx) | |
234 | : m_image_ctx(image_ctx), m_state(STATE_UNINITIALIZED), | |
9f95a23c | 235 | m_lock(ceph::make_mutex(util::unique_lock_name("librbd::ImageState::m_lock", this))), |
7c673cae | 236 | m_last_refresh(0), m_refresh_seq(0), |
11fdf7f2 | 237 | m_update_watchers(new ImageUpdateWatchers(image_ctx->cct)) { |
7c673cae FG |
238 | } |
239 | ||
240 | template <typename I> | |
241 | ImageState<I>::~ImageState() { | |
11fdf7f2 | 242 | ceph_assert(m_state == STATE_UNINITIALIZED || m_state == STATE_CLOSED); |
7c673cae FG |
243 | delete m_update_watchers; |
244 | } | |
245 | ||
246 | template <typename I> | |
11fdf7f2 | 247 | int ImageState<I>::open(uint64_t flags) { |
7c673cae | 248 | C_SaferCond ctx; |
11fdf7f2 | 249 | open(flags, &ctx); |
7c673cae FG |
250 | |
251 | int r = ctx.wait(); | |
252 | if (r < 0) { | |
253 | delete m_image_ctx; | |
254 | } | |
255 | return r; | |
256 | } | |
257 | ||
258 | template <typename I> | |
11fdf7f2 | 259 | void ImageState<I>::open(uint64_t flags, Context *on_finish) { |
7c673cae FG |
260 | CephContext *cct = m_image_ctx->cct; |
261 | ldout(cct, 20) << __func__ << dendl; | |
262 | ||
9f95a23c | 263 | m_lock.lock(); |
11fdf7f2 TL |
264 | ceph_assert(m_state == STATE_UNINITIALIZED); |
265 | m_open_flags = flags; | |
7c673cae FG |
266 | |
267 | Action action(ACTION_TYPE_OPEN); | |
268 | action.refresh_seq = m_refresh_seq; | |
269 | ||
270 | execute_action_unlock(action, on_finish); | |
271 | } | |
272 | ||
273 | template <typename I> | |
274 | int ImageState<I>::close() { | |
275 | C_SaferCond ctx; | |
276 | close(&ctx); | |
277 | ||
278 | int r = ctx.wait(); | |
279 | delete m_image_ctx; | |
280 | return r; | |
281 | } | |
282 | ||
283 | template <typename I> | |
284 | void ImageState<I>::close(Context *on_finish) { | |
285 | CephContext *cct = m_image_ctx->cct; | |
286 | ldout(cct, 20) << __func__ << dendl; | |
287 | ||
9f95a23c | 288 | m_lock.lock(); |
11fdf7f2 | 289 | ceph_assert(!is_closed()); |
7c673cae FG |
290 | |
291 | Action action(ACTION_TYPE_CLOSE); | |
292 | action.refresh_seq = m_refresh_seq; | |
293 | execute_action_unlock(action, on_finish); | |
294 | } | |
295 | ||
296 | template <typename I> | |
297 | void ImageState<I>::handle_update_notification() { | |
9f95a23c | 298 | std::lock_guard locker{m_lock}; |
7c673cae FG |
299 | ++m_refresh_seq; |
300 | ||
301 | CephContext *cct = m_image_ctx->cct; | |
302 | ldout(cct, 20) << __func__ << ": refresh_seq = " << m_refresh_seq << ", " | |
303 | << "last_refresh = " << m_last_refresh << dendl; | |
304 | ||
9f95a23c TL |
305 | switch (m_state) { |
306 | case STATE_UNINITIALIZED: | |
307 | case STATE_CLOSED: | |
308 | case STATE_OPENING: | |
309 | case STATE_CLOSING: | |
310 | ldout(cct, 5) << "dropping update notification to watchers" << dendl; | |
311 | return; | |
312 | default: | |
313 | break; | |
7c673cae | 314 | } |
9f95a23c TL |
315 | |
316 | m_update_watchers->notify(); | |
7c673cae FG |
317 | } |
318 | ||
319 | template <typename I> | |
320 | bool ImageState<I>::is_refresh_required() const { | |
9f95a23c | 321 | std::lock_guard locker{m_lock}; |
7c673cae FG |
322 | return (m_last_refresh != m_refresh_seq || find_pending_refresh() != nullptr); |
323 | } | |
324 | ||
325 | template <typename I> | |
326 | int ImageState<I>::refresh() { | |
327 | C_SaferCond refresh_ctx; | |
328 | refresh(&refresh_ctx); | |
329 | return refresh_ctx.wait(); | |
330 | } | |
331 | ||
332 | template <typename I> | |
333 | void ImageState<I>::refresh(Context *on_finish) { | |
334 | CephContext *cct = m_image_ctx->cct; | |
335 | ldout(cct, 20) << __func__ << dendl; | |
336 | ||
9f95a23c | 337 | m_lock.lock(); |
7c673cae | 338 | if (is_closed()) { |
9f95a23c | 339 | m_lock.unlock(); |
7c673cae FG |
340 | on_finish->complete(-ESHUTDOWN); |
341 | return; | |
342 | } | |
343 | ||
344 | Action action(ACTION_TYPE_REFRESH); | |
345 | action.refresh_seq = m_refresh_seq; | |
346 | execute_action_unlock(action, on_finish); | |
347 | } | |
348 | ||
349 | template <typename I> | |
350 | int ImageState<I>::refresh_if_required() { | |
351 | C_SaferCond ctx; | |
352 | { | |
9f95a23c | 353 | m_lock.lock(); |
7c673cae FG |
354 | Action action(ACTION_TYPE_REFRESH); |
355 | action.refresh_seq = m_refresh_seq; | |
356 | ||
357 | auto refresh_action = find_pending_refresh(); | |
358 | if (refresh_action != nullptr) { | |
359 | // if a refresh is in-flight, delay until it is finished | |
360 | action = *refresh_action; | |
361 | } else if (m_last_refresh == m_refresh_seq) { | |
9f95a23c | 362 | m_lock.unlock(); |
7c673cae FG |
363 | return 0; |
364 | } else if (is_closed()) { | |
9f95a23c | 365 | m_lock.unlock(); |
7c673cae FG |
366 | return -ESHUTDOWN; |
367 | } | |
368 | ||
369 | execute_action_unlock(action, &ctx); | |
370 | } | |
371 | ||
372 | return ctx.wait(); | |
373 | } | |
374 | ||
375 | template <typename I> | |
376 | const typename ImageState<I>::Action * | |
377 | ImageState<I>::find_pending_refresh() const { | |
9f95a23c | 378 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
379 | |
380 | auto it = std::find_if(m_actions_contexts.rbegin(), | |
381 | m_actions_contexts.rend(), | |
382 | [](const ActionContexts& action_contexts) { | |
383 | return (action_contexts.first == ACTION_TYPE_REFRESH); | |
384 | }); | |
385 | if (it != m_actions_contexts.rend()) { | |
386 | return &it->first; | |
387 | } | |
388 | return nullptr; | |
389 | } | |
390 | ||
391 | template <typename I> | |
11fdf7f2 | 392 | void ImageState<I>::snap_set(uint64_t snap_id, Context *on_finish) { |
7c673cae | 393 | CephContext *cct = m_image_ctx->cct; |
11fdf7f2 | 394 | ldout(cct, 20) << __func__ << ": snap_id=" << snap_id << dendl; |
7c673cae FG |
395 | |
396 | Action action(ACTION_TYPE_SET_SNAP); | |
11fdf7f2 | 397 | action.snap_id = snap_id; |
7c673cae | 398 | |
9f95a23c | 399 | m_lock.lock(); |
7c673cae FG |
400 | execute_action_unlock(action, on_finish); |
401 | } | |
402 | ||
403 | template <typename I> | |
404 | void ImageState<I>::prepare_lock(Context *on_ready) { | |
405 | CephContext *cct = m_image_ctx->cct; | |
406 | ldout(cct, 10) << __func__ << dendl; | |
407 | ||
9f95a23c | 408 | m_lock.lock(); |
7c673cae | 409 | if (is_closed()) { |
9f95a23c | 410 | m_lock.unlock(); |
7c673cae FG |
411 | on_ready->complete(-ESHUTDOWN); |
412 | return; | |
413 | } | |
414 | ||
415 | Action action(ACTION_TYPE_LOCK); | |
416 | action.on_ready = on_ready; | |
417 | execute_action_unlock(action, nullptr); | |
418 | } | |
419 | ||
420 | template <typename I> | |
421 | void ImageState<I>::handle_prepare_lock_complete() { | |
422 | CephContext *cct = m_image_ctx->cct; | |
423 | ldout(cct, 10) << __func__ << dendl; | |
424 | ||
9f95a23c | 425 | m_lock.lock(); |
7c673cae | 426 | if (m_state != STATE_PREPARING_LOCK) { |
9f95a23c | 427 | m_lock.unlock(); |
7c673cae FG |
428 | return; |
429 | } | |
430 | ||
431 | complete_action_unlock(STATE_OPEN, 0); | |
432 | } | |
433 | ||
434 | template <typename I> | |
435 | int ImageState<I>::register_update_watcher(UpdateWatchCtx *watcher, | |
436 | uint64_t *handle) { | |
437 | CephContext *cct = m_image_ctx->cct; | |
438 | ldout(cct, 20) << __func__ << dendl; | |
439 | ||
440 | m_update_watchers->register_watcher(watcher, handle); | |
441 | ||
442 | ldout(cct, 20) << __func__ << ": handle=" << *handle << dendl; | |
443 | return 0; | |
444 | } | |
445 | ||
446 | template <typename I> | |
9f95a23c TL |
447 | void ImageState<I>::unregister_update_watcher(uint64_t handle, |
448 | Context *on_finish) { | |
7c673cae FG |
449 | CephContext *cct = m_image_ctx->cct; |
450 | ldout(cct, 20) << __func__ << ": handle=" << handle << dendl; | |
451 | ||
9f95a23c TL |
452 | m_update_watchers->unregister_watcher(handle, on_finish); |
453 | } | |
454 | ||
455 | template <typename I> | |
456 | int ImageState<I>::unregister_update_watcher(uint64_t handle) { | |
7c673cae | 457 | C_SaferCond ctx; |
9f95a23c | 458 | unregister_update_watcher(handle, &ctx); |
7c673cae FG |
459 | return ctx.wait(); |
460 | } | |
461 | ||
462 | template <typename I> | |
463 | void ImageState<I>::flush_update_watchers(Context *on_finish) { | |
464 | CephContext *cct = m_image_ctx->cct; | |
465 | ldout(cct, 20) << __func__ << dendl; | |
466 | ||
467 | m_update_watchers->flush(on_finish); | |
468 | } | |
469 | ||
470 | template <typename I> | |
471 | void ImageState<I>::shut_down_update_watchers(Context *on_finish) { | |
472 | CephContext *cct = m_image_ctx->cct; | |
473 | ldout(cct, 20) << __func__ << dendl; | |
474 | ||
475 | m_update_watchers->shut_down(on_finish); | |
476 | } | |
477 | ||
478 | template <typename I> | |
479 | bool ImageState<I>::is_transition_state() const { | |
480 | switch (m_state) { | |
481 | case STATE_UNINITIALIZED: | |
482 | case STATE_OPEN: | |
483 | case STATE_CLOSED: | |
484 | return false; | |
485 | case STATE_OPENING: | |
486 | case STATE_CLOSING: | |
487 | case STATE_REFRESHING: | |
488 | case STATE_SETTING_SNAP: | |
489 | case STATE_PREPARING_LOCK: | |
490 | break; | |
491 | } | |
492 | return true; | |
493 | } | |
494 | ||
495 | template <typename I> | |
496 | bool ImageState<I>::is_closed() const { | |
9f95a23c | 497 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
498 | |
499 | return ((m_state == STATE_CLOSED) || | |
500 | (!m_actions_contexts.empty() && | |
501 | m_actions_contexts.back().first.action_type == ACTION_TYPE_CLOSE)); | |
502 | } | |
503 | ||
504 | template <typename I> | |
505 | void ImageState<I>::append_context(const Action &action, Context *context) { | |
9f95a23c | 506 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
507 | |
508 | ActionContexts *action_contexts = nullptr; | |
509 | for (auto &action_ctxs : m_actions_contexts) { | |
510 | if (action == action_ctxs.first) { | |
511 | action_contexts = &action_ctxs; | |
512 | break; | |
513 | } | |
514 | } | |
515 | ||
516 | if (action_contexts == nullptr) { | |
517 | m_actions_contexts.push_back({action, {}}); | |
518 | action_contexts = &m_actions_contexts.back(); | |
519 | } | |
520 | ||
521 | if (context != nullptr) { | |
522 | action_contexts->second.push_back(context); | |
523 | } | |
524 | } | |
525 | ||
526 | template <typename I> | |
527 | void ImageState<I>::execute_next_action_unlock() { | |
9f95a23c | 528 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
11fdf7f2 | 529 | ceph_assert(!m_actions_contexts.empty()); |
7c673cae FG |
530 | switch (m_actions_contexts.front().first.action_type) { |
531 | case ACTION_TYPE_OPEN: | |
532 | send_open_unlock(); | |
533 | return; | |
534 | case ACTION_TYPE_CLOSE: | |
535 | send_close_unlock(); | |
536 | return; | |
537 | case ACTION_TYPE_REFRESH: | |
538 | send_refresh_unlock(); | |
539 | return; | |
540 | case ACTION_TYPE_SET_SNAP: | |
541 | send_set_snap_unlock(); | |
542 | return; | |
543 | case ACTION_TYPE_LOCK: | |
544 | send_prepare_lock_unlock(); | |
545 | return; | |
546 | } | |
11fdf7f2 | 547 | ceph_abort(); |
7c673cae FG |
548 | } |
549 | ||
550 | template <typename I> | |
551 | void ImageState<I>::execute_action_unlock(const Action &action, | |
552 | Context *on_finish) { | |
9f95a23c | 553 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
554 | |
555 | append_context(action, on_finish); | |
556 | if (!is_transition_state()) { | |
557 | execute_next_action_unlock(); | |
558 | } else { | |
9f95a23c | 559 | m_lock.unlock(); |
7c673cae FG |
560 | } |
561 | } | |
562 | ||
563 | template <typename I> | |
564 | void ImageState<I>::complete_action_unlock(State next_state, int r) { | |
9f95a23c | 565 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
11fdf7f2 | 566 | ceph_assert(!m_actions_contexts.empty()); |
7c673cae FG |
567 | |
568 | ActionContexts action_contexts(std::move(m_actions_contexts.front())); | |
569 | m_actions_contexts.pop_front(); | |
570 | ||
571 | m_state = next_state; | |
9f95a23c | 572 | m_lock.unlock(); |
7c673cae FG |
573 | |
574 | for (auto ctx : action_contexts.second) { | |
575 | ctx->complete(r); | |
576 | } | |
577 | ||
578 | if (next_state != STATE_UNINITIALIZED && next_state != STATE_CLOSED) { | |
9f95a23c | 579 | m_lock.lock(); |
7c673cae FG |
580 | if (!is_transition_state() && !m_actions_contexts.empty()) { |
581 | execute_next_action_unlock(); | |
582 | } else { | |
9f95a23c | 583 | m_lock.unlock(); |
7c673cae FG |
584 | } |
585 | } | |
586 | } | |
587 | ||
588 | template <typename I> | |
589 | void ImageState<I>::send_open_unlock() { | |
9f95a23c | 590 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
591 | CephContext *cct = m_image_ctx->cct; |
592 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
593 | ||
594 | m_state = STATE_OPENING; | |
595 | ||
596 | Context *ctx = create_async_context_callback( | |
597 | *m_image_ctx, create_context_callback< | |
598 | ImageState<I>, &ImageState<I>::handle_open>(this)); | |
599 | image::OpenRequest<I> *req = image::OpenRequest<I>::create( | |
11fdf7f2 | 600 | m_image_ctx, m_open_flags, ctx); |
7c673cae | 601 | |
9f95a23c | 602 | m_lock.unlock(); |
7c673cae FG |
603 | req->send(); |
604 | } | |
605 | ||
606 | template <typename I> | |
607 | void ImageState<I>::handle_open(int r) { | |
608 | CephContext *cct = m_image_ctx->cct; | |
609 | ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; | |
610 | ||
611 | if (r < 0 && r != -ENOENT) { | |
612 | lderr(cct) << "failed to open image: " << cpp_strerror(r) << dendl; | |
613 | } | |
614 | ||
9f95a23c | 615 | m_lock.lock(); |
7c673cae FG |
616 | complete_action_unlock(r < 0 ? STATE_UNINITIALIZED : STATE_OPEN, r); |
617 | } | |
618 | ||
619 | template <typename I> | |
620 | void ImageState<I>::send_close_unlock() { | |
9f95a23c | 621 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
622 | CephContext *cct = m_image_ctx->cct; |
623 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
624 | ||
625 | m_state = STATE_CLOSING; | |
626 | ||
627 | Context *ctx = create_context_callback< | |
628 | ImageState<I>, &ImageState<I>::handle_close>(this); | |
629 | image::CloseRequest<I> *req = image::CloseRequest<I>::create( | |
630 | m_image_ctx, ctx); | |
631 | ||
9f95a23c | 632 | m_lock.unlock(); |
7c673cae FG |
633 | req->send(); |
634 | } | |
635 | ||
636 | template <typename I> | |
637 | void ImageState<I>::handle_close(int r) { | |
638 | CephContext *cct = m_image_ctx->cct; | |
639 | ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; | |
640 | ||
641 | if (r < 0) { | |
642 | lderr(cct) << "error occurred while closing image: " << cpp_strerror(r) | |
643 | << dendl; | |
644 | } | |
645 | ||
9f95a23c | 646 | m_lock.lock(); |
7c673cae FG |
647 | complete_action_unlock(STATE_CLOSED, r); |
648 | } | |
649 | ||
650 | template <typename I> | |
651 | void ImageState<I>::send_refresh_unlock() { | |
9f95a23c | 652 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
653 | CephContext *cct = m_image_ctx->cct; |
654 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
655 | ||
656 | m_state = STATE_REFRESHING; | |
11fdf7f2 | 657 | ceph_assert(!m_actions_contexts.empty()); |
7c673cae | 658 | auto &action_context = m_actions_contexts.front().first; |
11fdf7f2 | 659 | ceph_assert(action_context.action_type == ACTION_TYPE_REFRESH); |
7c673cae FG |
660 | |
661 | Context *ctx = create_async_context_callback( | |
662 | *m_image_ctx, create_context_callback< | |
663 | ImageState<I>, &ImageState<I>::handle_refresh>(this)); | |
664 | image::RefreshRequest<I> *req = image::RefreshRequest<I>::create( | |
665 | *m_image_ctx, false, false, ctx); | |
666 | ||
9f95a23c | 667 | m_lock.unlock(); |
7c673cae FG |
668 | req->send(); |
669 | } | |
670 | ||
671 | template <typename I> | |
672 | void ImageState<I>::handle_refresh(int r) { | |
673 | CephContext *cct = m_image_ctx->cct; | |
674 | ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; | |
675 | ||
9f95a23c | 676 | m_lock.lock(); |
11fdf7f2 | 677 | ceph_assert(!m_actions_contexts.empty()); |
7c673cae FG |
678 | |
679 | ActionContexts &action_contexts(m_actions_contexts.front()); | |
11fdf7f2 TL |
680 | ceph_assert(action_contexts.first.action_type == ACTION_TYPE_REFRESH); |
681 | ceph_assert(m_last_refresh <= action_contexts.first.refresh_seq); | |
7c673cae FG |
682 | |
683 | if (r == -ERESTART) { | |
684 | ldout(cct, 5) << "incomplete refresh: not updating sequence" << dendl; | |
685 | r = 0; | |
686 | } else { | |
687 | m_last_refresh = action_contexts.first.refresh_seq; | |
688 | } | |
689 | ||
690 | complete_action_unlock(STATE_OPEN, r); | |
691 | } | |
692 | ||
693 | template <typename I> | |
694 | void ImageState<I>::send_set_snap_unlock() { | |
9f95a23c | 695 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
696 | |
697 | m_state = STATE_SETTING_SNAP; | |
698 | ||
11fdf7f2 | 699 | ceph_assert(!m_actions_contexts.empty()); |
7c673cae | 700 | ActionContexts &action_contexts(m_actions_contexts.front()); |
11fdf7f2 | 701 | ceph_assert(action_contexts.first.action_type == ACTION_TYPE_SET_SNAP); |
7c673cae FG |
702 | |
703 | CephContext *cct = m_image_ctx->cct; | |
704 | ldout(cct, 10) << this << " " << __func__ << ": " | |
11fdf7f2 | 705 | << "snap_id=" << action_contexts.first.snap_id << dendl; |
7c673cae FG |
706 | |
707 | Context *ctx = create_async_context_callback( | |
708 | *m_image_ctx, create_context_callback< | |
709 | ImageState<I>, &ImageState<I>::handle_set_snap>(this)); | |
710 | image::SetSnapRequest<I> *req = image::SetSnapRequest<I>::create( | |
11fdf7f2 | 711 | *m_image_ctx, action_contexts.first.snap_id, ctx); |
7c673cae | 712 | |
9f95a23c | 713 | m_lock.unlock(); |
7c673cae FG |
714 | req->send(); |
715 | } | |
716 | ||
717 | template <typename I> | |
718 | void ImageState<I>::handle_set_snap(int r) { | |
719 | CephContext *cct = m_image_ctx->cct; | |
720 | ldout(cct, 10) << this << " " << __func__ << " r=" << r << dendl; | |
721 | ||
722 | if (r < 0 && r != -ENOENT) { | |
723 | lderr(cct) << "failed to set snapshot: " << cpp_strerror(r) << dendl; | |
724 | } | |
725 | ||
9f95a23c | 726 | m_lock.lock(); |
7c673cae FG |
727 | complete_action_unlock(STATE_OPEN, r); |
728 | } | |
729 | ||
730 | template <typename I> | |
731 | void ImageState<I>::send_prepare_lock_unlock() { | |
732 | CephContext *cct = m_image_ctx->cct; | |
733 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
734 | ||
9f95a23c | 735 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
736 | m_state = STATE_PREPARING_LOCK; |
737 | ||
11fdf7f2 | 738 | ceph_assert(!m_actions_contexts.empty()); |
7c673cae | 739 | ActionContexts &action_contexts(m_actions_contexts.front()); |
11fdf7f2 | 740 | ceph_assert(action_contexts.first.action_type == ACTION_TYPE_LOCK); |
7c673cae FG |
741 | |
742 | Context *on_ready = action_contexts.first.on_ready; | |
9f95a23c | 743 | m_lock.unlock(); |
7c673cae FG |
744 | |
745 | if (on_ready == nullptr) { | |
746 | complete_action_unlock(STATE_OPEN, 0); | |
747 | return; | |
748 | } | |
749 | ||
750 | // wake up the lock handler now that its safe to proceed | |
751 | on_ready->complete(0); | |
752 | } | |
753 | ||
754 | } // namespace librbd | |
755 | ||
756 | template class librbd::ImageState<librbd::ImageCtx>; |