]>
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 | ||
29 | ImageUpdateWatchers(CephContext *cct) : m_cct(cct), | |
30 | m_lock(util::unique_lock_name("librbd::ImageUpdateWatchers::m_lock", this)) { | |
31 | } | |
32 | ||
33 | ~ImageUpdateWatchers() { | |
34 | assert(m_watchers.empty()); | |
35 | assert(m_in_flight.empty()); | |
36 | assert(m_pending_unregister.empty()); | |
37 | assert(m_on_shut_down_finish == nullptr); | |
38 | ||
39 | destroy_work_queue(); | |
40 | } | |
41 | ||
42 | void flush(Context *on_finish) { | |
43 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << dendl; | |
44 | { | |
45 | Mutex::Locker locker(m_lock); | |
46 | if (!m_in_flight.empty()) { | |
47 | Context *ctx = new FunctionContext( | |
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 | { | |
65 | Mutex::Locker locker(m_lock); | |
66 | assert(m_on_shut_down_finish == nullptr); | |
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 | ||
81 | Mutex::Locker locker(m_lock); | |
82 | assert(m_on_shut_down_finish == nullptr); | |
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 | { | |
95 | Mutex::Locker locker(m_lock); | |
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()) { | |
101 | assert(m_pending_unregister.find(handle) == m_pending_unregister.end()); | |
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 | ||
119 | Mutex::Locker locker(m_lock); | |
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) { | |
126 | assert(m_lock.is_locked()); | |
127 | ||
128 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << ": handle=" | |
129 | << handle << ", watcher=" << watcher << dendl; | |
130 | ||
131 | m_in_flight.insert(handle); | |
132 | ||
133 | Context *ctx = new FunctionContext( | |
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 | { | |
152 | Mutex::Locker locker(m_lock); | |
153 | ||
154 | auto in_flight_it = m_in_flight.find(handle); | |
155 | assert(in_flight_it != m_in_flight.end()); | |
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()) { | |
169 | assert(m_pending_unregister.empty()); | |
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; | |
203 | Mutex m_lock; | |
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 | } | |
215 | ThreadPoolSingleton *thread_pool_singleton; | |
216 | m_cct->lookup_or_create_singleton_object<ThreadPoolSingleton>( | |
217 | thread_pool_singleton, "librbd::ImageUpdateWatchers::thread_pool"); | |
218 | m_work_queue = new ContextWQ("librbd::ImageUpdateWatchers::op_work_queue", | |
181888fb | 219 | m_cct->_conf->get_val<int64_t>("rbd_op_thread_timeout"), |
7c673cae FG |
220 | thread_pool_singleton); |
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), | |
235 | m_lock(util::unique_lock_name("librbd::ImageState::m_lock", this)), | |
236 | m_last_refresh(0), m_refresh_seq(0), | |
237 | m_update_watchers(new ImageUpdateWatchers(image_ctx->cct)), | |
238 | m_skip_open_parent_image(false) { | |
239 | } | |
240 | ||
241 | template <typename I> | |
242 | ImageState<I>::~ImageState() { | |
243 | assert(m_state == STATE_UNINITIALIZED || m_state == STATE_CLOSED); | |
244 | delete m_update_watchers; | |
245 | } | |
246 | ||
247 | template <typename I> | |
248 | int ImageState<I>::open(bool skip_open_parent) { | |
249 | C_SaferCond ctx; | |
250 | open(skip_open_parent, &ctx); | |
251 | ||
252 | int r = ctx.wait(); | |
253 | if (r < 0) { | |
254 | delete m_image_ctx; | |
255 | } | |
256 | return r; | |
257 | } | |
258 | ||
259 | template <typename I> | |
260 | void ImageState<I>::open(bool skip_open_parent, Context *on_finish) { | |
261 | CephContext *cct = m_image_ctx->cct; | |
262 | ldout(cct, 20) << __func__ << dendl; | |
263 | ||
264 | m_lock.Lock(); | |
265 | assert(m_state == STATE_UNINITIALIZED); | |
266 | m_skip_open_parent_image = skip_open_parent; | |
267 | ||
268 | Action action(ACTION_TYPE_OPEN); | |
269 | action.refresh_seq = m_refresh_seq; | |
270 | ||
271 | execute_action_unlock(action, on_finish); | |
272 | } | |
273 | ||
274 | template <typename I> | |
275 | int ImageState<I>::close() { | |
276 | C_SaferCond ctx; | |
277 | close(&ctx); | |
278 | ||
279 | int r = ctx.wait(); | |
280 | delete m_image_ctx; | |
281 | return r; | |
282 | } | |
283 | ||
284 | template <typename I> | |
285 | void ImageState<I>::close(Context *on_finish) { | |
286 | CephContext *cct = m_image_ctx->cct; | |
287 | ldout(cct, 20) << __func__ << dendl; | |
288 | ||
289 | m_lock.Lock(); | |
290 | assert(!is_closed()); | |
291 | ||
292 | Action action(ACTION_TYPE_CLOSE); | |
293 | action.refresh_seq = m_refresh_seq; | |
294 | execute_action_unlock(action, on_finish); | |
295 | } | |
296 | ||
297 | template <typename I> | |
298 | void ImageState<I>::handle_update_notification() { | |
299 | Mutex::Locker locker(m_lock); | |
300 | ++m_refresh_seq; | |
301 | ||
302 | CephContext *cct = m_image_ctx->cct; | |
303 | ldout(cct, 20) << __func__ << ": refresh_seq = " << m_refresh_seq << ", " | |
304 | << "last_refresh = " << m_last_refresh << dendl; | |
305 | ||
306 | if (m_state == STATE_OPEN) { | |
307 | m_update_watchers->notify(); | |
308 | } | |
309 | } | |
310 | ||
311 | template <typename I> | |
312 | bool ImageState<I>::is_refresh_required() const { | |
313 | Mutex::Locker locker(m_lock); | |
314 | return (m_last_refresh != m_refresh_seq || find_pending_refresh() != nullptr); | |
315 | } | |
316 | ||
317 | template <typename I> | |
318 | int ImageState<I>::refresh() { | |
319 | C_SaferCond refresh_ctx; | |
320 | refresh(&refresh_ctx); | |
321 | return refresh_ctx.wait(); | |
322 | } | |
323 | ||
324 | template <typename I> | |
325 | void ImageState<I>::refresh(Context *on_finish) { | |
326 | CephContext *cct = m_image_ctx->cct; | |
327 | ldout(cct, 20) << __func__ << dendl; | |
328 | ||
329 | m_lock.Lock(); | |
330 | if (is_closed()) { | |
331 | m_lock.Unlock(); | |
332 | on_finish->complete(-ESHUTDOWN); | |
333 | return; | |
334 | } | |
335 | ||
336 | Action action(ACTION_TYPE_REFRESH); | |
337 | action.refresh_seq = m_refresh_seq; | |
338 | execute_action_unlock(action, on_finish); | |
339 | } | |
340 | ||
341 | template <typename I> | |
342 | int ImageState<I>::refresh_if_required() { | |
343 | C_SaferCond ctx; | |
344 | { | |
345 | m_lock.Lock(); | |
346 | Action action(ACTION_TYPE_REFRESH); | |
347 | action.refresh_seq = m_refresh_seq; | |
348 | ||
349 | auto refresh_action = find_pending_refresh(); | |
350 | if (refresh_action != nullptr) { | |
351 | // if a refresh is in-flight, delay until it is finished | |
352 | action = *refresh_action; | |
353 | } else if (m_last_refresh == m_refresh_seq) { | |
354 | m_lock.Unlock(); | |
355 | return 0; | |
356 | } else if (is_closed()) { | |
357 | m_lock.Unlock(); | |
358 | return -ESHUTDOWN; | |
359 | } | |
360 | ||
361 | execute_action_unlock(action, &ctx); | |
362 | } | |
363 | ||
364 | return ctx.wait(); | |
365 | } | |
366 | ||
367 | template <typename I> | |
368 | const typename ImageState<I>::Action * | |
369 | ImageState<I>::find_pending_refresh() const { | |
370 | assert(m_lock.is_locked()); | |
371 | ||
372 | auto it = std::find_if(m_actions_contexts.rbegin(), | |
373 | m_actions_contexts.rend(), | |
374 | [](const ActionContexts& action_contexts) { | |
375 | return (action_contexts.first == ACTION_TYPE_REFRESH); | |
376 | }); | |
377 | if (it != m_actions_contexts.rend()) { | |
378 | return &it->first; | |
379 | } | |
380 | return nullptr; | |
381 | } | |
382 | ||
383 | template <typename I> | |
384 | void ImageState<I>::snap_set(const cls::rbd::SnapshotNamespace &snap_namespace, | |
385 | const std::string &snap_name, | |
386 | Context *on_finish) { | |
387 | CephContext *cct = m_image_ctx->cct; | |
388 | ldout(cct, 20) << __func__ << ": snap_name=" << snap_name << dendl; | |
389 | ||
390 | Action action(ACTION_TYPE_SET_SNAP); | |
391 | action.snap_namespace = snap_namespace; | |
392 | action.snap_name = snap_name; | |
393 | ||
394 | m_lock.Lock(); | |
395 | execute_action_unlock(action, on_finish); | |
396 | } | |
397 | ||
398 | template <typename I> | |
399 | void ImageState<I>::prepare_lock(Context *on_ready) { | |
400 | CephContext *cct = m_image_ctx->cct; | |
401 | ldout(cct, 10) << __func__ << dendl; | |
402 | ||
403 | m_lock.Lock(); | |
404 | if (is_closed()) { | |
405 | m_lock.Unlock(); | |
406 | on_ready->complete(-ESHUTDOWN); | |
407 | return; | |
408 | } | |
409 | ||
410 | Action action(ACTION_TYPE_LOCK); | |
411 | action.on_ready = on_ready; | |
412 | execute_action_unlock(action, nullptr); | |
413 | } | |
414 | ||
415 | template <typename I> | |
416 | void ImageState<I>::handle_prepare_lock_complete() { | |
417 | CephContext *cct = m_image_ctx->cct; | |
418 | ldout(cct, 10) << __func__ << dendl; | |
419 | ||
420 | m_lock.Lock(); | |
421 | if (m_state != STATE_PREPARING_LOCK) { | |
422 | m_lock.Unlock(); | |
423 | return; | |
424 | } | |
425 | ||
426 | complete_action_unlock(STATE_OPEN, 0); | |
427 | } | |
428 | ||
429 | template <typename I> | |
430 | int ImageState<I>::register_update_watcher(UpdateWatchCtx *watcher, | |
431 | uint64_t *handle) { | |
432 | CephContext *cct = m_image_ctx->cct; | |
433 | ldout(cct, 20) << __func__ << dendl; | |
434 | ||
435 | m_update_watchers->register_watcher(watcher, handle); | |
436 | ||
437 | ldout(cct, 20) << __func__ << ": handle=" << *handle << dendl; | |
438 | return 0; | |
439 | } | |
440 | ||
441 | template <typename I> | |
442 | int ImageState<I>::unregister_update_watcher(uint64_t handle) { | |
443 | CephContext *cct = m_image_ctx->cct; | |
444 | ldout(cct, 20) << __func__ << ": handle=" << handle << dendl; | |
445 | ||
446 | C_SaferCond ctx; | |
447 | m_update_watchers->unregister_watcher(handle, &ctx); | |
448 | return ctx.wait(); | |
449 | } | |
450 | ||
451 | template <typename I> | |
452 | void ImageState<I>::flush_update_watchers(Context *on_finish) { | |
453 | CephContext *cct = m_image_ctx->cct; | |
454 | ldout(cct, 20) << __func__ << dendl; | |
455 | ||
456 | m_update_watchers->flush(on_finish); | |
457 | } | |
458 | ||
459 | template <typename I> | |
460 | void ImageState<I>::shut_down_update_watchers(Context *on_finish) { | |
461 | CephContext *cct = m_image_ctx->cct; | |
462 | ldout(cct, 20) << __func__ << dendl; | |
463 | ||
464 | m_update_watchers->shut_down(on_finish); | |
465 | } | |
466 | ||
467 | template <typename I> | |
468 | bool ImageState<I>::is_transition_state() const { | |
469 | switch (m_state) { | |
470 | case STATE_UNINITIALIZED: | |
471 | case STATE_OPEN: | |
472 | case STATE_CLOSED: | |
473 | return false; | |
474 | case STATE_OPENING: | |
475 | case STATE_CLOSING: | |
476 | case STATE_REFRESHING: | |
477 | case STATE_SETTING_SNAP: | |
478 | case STATE_PREPARING_LOCK: | |
479 | break; | |
480 | } | |
481 | return true; | |
482 | } | |
483 | ||
484 | template <typename I> | |
485 | bool ImageState<I>::is_closed() const { | |
486 | assert(m_lock.is_locked()); | |
487 | ||
488 | return ((m_state == STATE_CLOSED) || | |
489 | (!m_actions_contexts.empty() && | |
490 | m_actions_contexts.back().first.action_type == ACTION_TYPE_CLOSE)); | |
491 | } | |
492 | ||
493 | template <typename I> | |
494 | void ImageState<I>::append_context(const Action &action, Context *context) { | |
495 | assert(m_lock.is_locked()); | |
496 | ||
497 | ActionContexts *action_contexts = nullptr; | |
498 | for (auto &action_ctxs : m_actions_contexts) { | |
499 | if (action == action_ctxs.first) { | |
500 | action_contexts = &action_ctxs; | |
501 | break; | |
502 | } | |
503 | } | |
504 | ||
505 | if (action_contexts == nullptr) { | |
506 | m_actions_contexts.push_back({action, {}}); | |
507 | action_contexts = &m_actions_contexts.back(); | |
508 | } | |
509 | ||
510 | if (context != nullptr) { | |
511 | action_contexts->second.push_back(context); | |
512 | } | |
513 | } | |
514 | ||
515 | template <typename I> | |
516 | void ImageState<I>::execute_next_action_unlock() { | |
517 | assert(m_lock.is_locked()); | |
518 | assert(!m_actions_contexts.empty()); | |
519 | switch (m_actions_contexts.front().first.action_type) { | |
520 | case ACTION_TYPE_OPEN: | |
521 | send_open_unlock(); | |
522 | return; | |
523 | case ACTION_TYPE_CLOSE: | |
524 | send_close_unlock(); | |
525 | return; | |
526 | case ACTION_TYPE_REFRESH: | |
527 | send_refresh_unlock(); | |
528 | return; | |
529 | case ACTION_TYPE_SET_SNAP: | |
530 | send_set_snap_unlock(); | |
531 | return; | |
532 | case ACTION_TYPE_LOCK: | |
533 | send_prepare_lock_unlock(); | |
534 | return; | |
535 | } | |
536 | assert(false); | |
537 | } | |
538 | ||
539 | template <typename I> | |
540 | void ImageState<I>::execute_action_unlock(const Action &action, | |
541 | Context *on_finish) { | |
542 | assert(m_lock.is_locked()); | |
543 | ||
544 | append_context(action, on_finish); | |
545 | if (!is_transition_state()) { | |
546 | execute_next_action_unlock(); | |
547 | } else { | |
548 | m_lock.Unlock(); | |
549 | } | |
550 | } | |
551 | ||
552 | template <typename I> | |
553 | void ImageState<I>::complete_action_unlock(State next_state, int r) { | |
554 | assert(m_lock.is_locked()); | |
555 | assert(!m_actions_contexts.empty()); | |
556 | ||
557 | ActionContexts action_contexts(std::move(m_actions_contexts.front())); | |
558 | m_actions_contexts.pop_front(); | |
559 | ||
560 | m_state = next_state; | |
561 | m_lock.Unlock(); | |
562 | ||
563 | for (auto ctx : action_contexts.second) { | |
564 | ctx->complete(r); | |
565 | } | |
566 | ||
567 | if (next_state != STATE_UNINITIALIZED && next_state != STATE_CLOSED) { | |
568 | m_lock.Lock(); | |
569 | if (!is_transition_state() && !m_actions_contexts.empty()) { | |
570 | execute_next_action_unlock(); | |
571 | } else { | |
572 | m_lock.Unlock(); | |
573 | } | |
574 | } | |
575 | } | |
576 | ||
577 | template <typename I> | |
578 | void ImageState<I>::send_open_unlock() { | |
579 | assert(m_lock.is_locked()); | |
580 | CephContext *cct = m_image_ctx->cct; | |
581 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
582 | ||
583 | m_state = STATE_OPENING; | |
584 | ||
585 | Context *ctx = create_async_context_callback( | |
586 | *m_image_ctx, create_context_callback< | |
587 | ImageState<I>, &ImageState<I>::handle_open>(this)); | |
588 | image::OpenRequest<I> *req = image::OpenRequest<I>::create( | |
589 | m_image_ctx, m_skip_open_parent_image, ctx); | |
590 | ||
591 | m_lock.Unlock(); | |
592 | req->send(); | |
593 | } | |
594 | ||
595 | template <typename I> | |
596 | void ImageState<I>::handle_open(int r) { | |
597 | CephContext *cct = m_image_ctx->cct; | |
598 | ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; | |
599 | ||
600 | if (r < 0 && r != -ENOENT) { | |
601 | lderr(cct) << "failed to open image: " << cpp_strerror(r) << dendl; | |
602 | } | |
603 | ||
604 | m_lock.Lock(); | |
605 | complete_action_unlock(r < 0 ? STATE_UNINITIALIZED : STATE_OPEN, r); | |
606 | } | |
607 | ||
608 | template <typename I> | |
609 | void ImageState<I>::send_close_unlock() { | |
610 | assert(m_lock.is_locked()); | |
611 | CephContext *cct = m_image_ctx->cct; | |
612 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
613 | ||
614 | m_state = STATE_CLOSING; | |
615 | ||
616 | Context *ctx = create_context_callback< | |
617 | ImageState<I>, &ImageState<I>::handle_close>(this); | |
618 | image::CloseRequest<I> *req = image::CloseRequest<I>::create( | |
619 | m_image_ctx, ctx); | |
620 | ||
621 | m_lock.Unlock(); | |
622 | req->send(); | |
623 | } | |
624 | ||
625 | template <typename I> | |
626 | void ImageState<I>::handle_close(int r) { | |
627 | CephContext *cct = m_image_ctx->cct; | |
628 | ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; | |
629 | ||
630 | if (r < 0) { | |
631 | lderr(cct) << "error occurred while closing image: " << cpp_strerror(r) | |
632 | << dendl; | |
633 | } | |
634 | ||
635 | m_lock.Lock(); | |
636 | complete_action_unlock(STATE_CLOSED, r); | |
637 | } | |
638 | ||
639 | template <typename I> | |
640 | void ImageState<I>::send_refresh_unlock() { | |
641 | assert(m_lock.is_locked()); | |
642 | CephContext *cct = m_image_ctx->cct; | |
643 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
644 | ||
645 | m_state = STATE_REFRESHING; | |
646 | assert(!m_actions_contexts.empty()); | |
647 | auto &action_context = m_actions_contexts.front().first; | |
648 | assert(action_context.action_type == ACTION_TYPE_REFRESH); | |
649 | ||
650 | Context *ctx = create_async_context_callback( | |
651 | *m_image_ctx, create_context_callback< | |
652 | ImageState<I>, &ImageState<I>::handle_refresh>(this)); | |
653 | image::RefreshRequest<I> *req = image::RefreshRequest<I>::create( | |
654 | *m_image_ctx, false, false, ctx); | |
655 | ||
656 | m_lock.Unlock(); | |
657 | req->send(); | |
658 | } | |
659 | ||
660 | template <typename I> | |
661 | void ImageState<I>::handle_refresh(int r) { | |
662 | CephContext *cct = m_image_ctx->cct; | |
663 | ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; | |
664 | ||
665 | m_lock.Lock(); | |
666 | assert(!m_actions_contexts.empty()); | |
667 | ||
668 | ActionContexts &action_contexts(m_actions_contexts.front()); | |
669 | assert(action_contexts.first.action_type == ACTION_TYPE_REFRESH); | |
670 | assert(m_last_refresh <= action_contexts.first.refresh_seq); | |
671 | ||
672 | if (r == -ERESTART) { | |
673 | ldout(cct, 5) << "incomplete refresh: not updating sequence" << dendl; | |
674 | r = 0; | |
675 | } else { | |
676 | m_last_refresh = action_contexts.first.refresh_seq; | |
677 | } | |
678 | ||
679 | complete_action_unlock(STATE_OPEN, r); | |
680 | } | |
681 | ||
682 | template <typename I> | |
683 | void ImageState<I>::send_set_snap_unlock() { | |
684 | assert(m_lock.is_locked()); | |
685 | ||
686 | m_state = STATE_SETTING_SNAP; | |
687 | ||
688 | assert(!m_actions_contexts.empty()); | |
689 | ActionContexts &action_contexts(m_actions_contexts.front()); | |
690 | assert(action_contexts.first.action_type == ACTION_TYPE_SET_SNAP); | |
691 | ||
692 | CephContext *cct = m_image_ctx->cct; | |
693 | ldout(cct, 10) << this << " " << __func__ << ": " | |
694 | << "snap_name=" << action_contexts.first.snap_name << dendl; | |
695 | ||
696 | Context *ctx = create_async_context_callback( | |
697 | *m_image_ctx, create_context_callback< | |
698 | ImageState<I>, &ImageState<I>::handle_set_snap>(this)); | |
699 | image::SetSnapRequest<I> *req = image::SetSnapRequest<I>::create( | |
700 | *m_image_ctx, action_contexts.first.snap_namespace, action_contexts.first.snap_name, ctx); | |
701 | ||
702 | m_lock.Unlock(); | |
703 | req->send(); | |
704 | } | |
705 | ||
706 | template <typename I> | |
707 | void ImageState<I>::handle_set_snap(int r) { | |
708 | CephContext *cct = m_image_ctx->cct; | |
709 | ldout(cct, 10) << this << " " << __func__ << " r=" << r << dendl; | |
710 | ||
711 | if (r < 0 && r != -ENOENT) { | |
712 | lderr(cct) << "failed to set snapshot: " << cpp_strerror(r) << dendl; | |
713 | } | |
714 | ||
715 | m_lock.Lock(); | |
716 | complete_action_unlock(STATE_OPEN, r); | |
717 | } | |
718 | ||
719 | template <typename I> | |
720 | void ImageState<I>::send_prepare_lock_unlock() { | |
721 | CephContext *cct = m_image_ctx->cct; | |
722 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
723 | ||
724 | assert(m_lock.is_locked()); | |
725 | m_state = STATE_PREPARING_LOCK; | |
726 | ||
727 | assert(!m_actions_contexts.empty()); | |
728 | ActionContexts &action_contexts(m_actions_contexts.front()); | |
729 | assert(action_contexts.first.action_type == ACTION_TYPE_LOCK); | |
730 | ||
731 | Context *on_ready = action_contexts.first.on_ready; | |
732 | m_lock.Unlock(); | |
733 | ||
734 | if (on_ready == nullptr) { | |
735 | complete_action_unlock(STATE_OPEN, 0); | |
736 | return; | |
737 | } | |
738 | ||
739 | // wake up the lock handler now that its safe to proceed | |
740 | on_ready->complete(0); | |
741 | } | |
742 | ||
743 | } // namespace librbd | |
744 | ||
745 | template class librbd::ImageState<librbd::ImageCtx>; |