1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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/AsioEngine.h"
11 #include "librbd/ImageCtx.h"
12 #include "librbd/TaskFinisher.h"
13 #include "librbd/Utils.h"
14 #include "librbd/asio/ContextWQ.h"
15 #include "librbd/image/CloseRequest.h"
16 #include "librbd/image/OpenRequest.h"
17 #include "librbd/image/RefreshRequest.h"
18 #include "librbd/image/SetSnapRequest.h"
20 #define dout_subsys ceph_subsys_rbd
22 #define dout_prefix *_dout << "librbd::ImageState: " << this << " "
26 using util::create_async_context_callback
;
27 using util::create_context_callback
;
29 class ImageUpdateWatchers
{
32 explicit ImageUpdateWatchers(CephContext
*cct
) : m_cct(cct
),
33 m_lock(ceph::make_mutex(util::unique_lock_name("librbd::ImageUpdateWatchers::m_lock", this))) {
36 ~ImageUpdateWatchers() {
37 ceph_assert(m_watchers
.empty());
38 ceph_assert(m_in_flight
.empty());
39 ceph_assert(m_pending_unregister
.empty());
40 ceph_assert(m_on_shut_down_finish
== nullptr);
45 void flush(Context
*on_finish
) {
46 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
<< dendl
;
48 std::lock_guard locker
{m_lock
};
49 if (!m_in_flight
.empty()) {
50 Context
*ctx
= new LambdaContext(
51 [this, on_finish
](int r
) {
52 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
53 << ": completing flush" << dendl
;
54 on_finish
->complete(r
);
56 m_work_queue
->queue(ctx
, 0);
60 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
61 << ": completing flush" << dendl
;
62 on_finish
->complete(0);
65 void shut_down(Context
*on_finish
) {
66 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
<< dendl
;
68 std::lock_guard locker
{m_lock
};
69 ceph_assert(m_on_shut_down_finish
== nullptr);
71 if (!m_in_flight
.empty()) {
72 m_on_shut_down_finish
= on_finish
;
76 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
77 << ": completing shut down" << dendl
;
78 on_finish
->complete(0);
81 void register_watcher(UpdateWatchCtx
*watcher
, uint64_t *handle
) {
82 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
<< ": watcher="
85 std::lock_guard locker
{m_lock
};
86 ceph_assert(m_on_shut_down_finish
== nullptr);
90 *handle
= m_next_handle
++;
91 m_watchers
.insert(std::make_pair(*handle
, watcher
));
94 void unregister_watcher(uint64_t handle
, Context
*on_finish
) {
95 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
<< ": handle="
99 std::lock_guard locker
{m_lock
};
100 auto it
= m_watchers
.find(handle
);
101 if (it
== m_watchers
.end()) {
104 if (m_in_flight
.find(handle
) != m_in_flight
.end()) {
105 ceph_assert(m_pending_unregister
.find(handle
) == m_pending_unregister
.end());
106 m_pending_unregister
[handle
] = on_finish
;
109 m_watchers
.erase(it
);
114 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
115 << ": completing unregister" << dendl
;
116 on_finish
->complete(r
);
121 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
<< dendl
;
123 std::lock_guard locker
{m_lock
};
124 for (auto it
: m_watchers
) {
125 send_notify(it
.first
, it
.second
);
129 void send_notify(uint64_t handle
, UpdateWatchCtx
*watcher
) {
130 ceph_assert(ceph_mutex_is_locked(m_lock
));
132 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
<< ": handle="
133 << handle
<< ", watcher=" << watcher
<< dendl
;
135 m_in_flight
.insert(handle
);
137 Context
*ctx
= new LambdaContext(
138 [this, handle
, watcher
](int r
) {
139 handle_notify(handle
, watcher
);
142 m_work_queue
->queue(ctx
, 0);
145 void handle_notify(uint64_t handle
, UpdateWatchCtx
*watcher
) {
147 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
<< ": handle="
148 << handle
<< ", watcher=" << watcher
<< dendl
;
150 watcher
->handle_notify();
152 Context
*on_unregister_finish
= nullptr;
153 Context
*on_shut_down_finish
= nullptr;
156 std::lock_guard locker
{m_lock
};
158 auto in_flight_it
= m_in_flight
.find(handle
);
159 ceph_assert(in_flight_it
!= m_in_flight
.end());
160 m_in_flight
.erase(in_flight_it
);
162 // If there is no more in flight notifications for this watcher
163 // and it is pending unregister, complete it now.
164 if (m_in_flight
.find(handle
) == m_in_flight
.end()) {
165 auto it
= m_pending_unregister
.find(handle
);
166 if (it
!= m_pending_unregister
.end()) {
167 on_unregister_finish
= it
->second
;
168 m_pending_unregister
.erase(it
);
172 if (m_in_flight
.empty()) {
173 ceph_assert(m_pending_unregister
.empty());
174 if (m_on_shut_down_finish
!= nullptr) {
175 std::swap(m_on_shut_down_finish
, on_shut_down_finish
);
180 if (on_unregister_finish
!= nullptr) {
181 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
182 << ": completing unregister" << dendl
;
183 on_unregister_finish
->complete(0);
186 if (on_shut_down_finish
!= nullptr) {
187 ldout(m_cct
, 20) << "ImageUpdateWatchers::" << __func__
188 << ": completing shut down" << dendl
;
189 on_shut_down_finish
->complete(0);
194 class ThreadPoolSingleton
: public ThreadPool
{
196 explicit ThreadPoolSingleton(CephContext
*cct
)
197 : ThreadPool(cct
, "librbd::ImageUpdateWatchers::thread_pool", "tp_librbd",
201 ~ThreadPoolSingleton() override
{
208 ContextWQ
*m_work_queue
= nullptr;
209 std::map
<uint64_t, UpdateWatchCtx
*> m_watchers
;
210 uint64_t m_next_handle
= 0;
211 std::multiset
<uint64_t> m_in_flight
;
212 std::map
<uint64_t, Context
*> m_pending_unregister
;
213 Context
*m_on_shut_down_finish
= nullptr;
215 void create_work_queue() {
216 if (m_work_queue
!= nullptr) {
219 auto& thread_pool
= m_cct
->lookup_or_create_singleton_object
<
220 ThreadPoolSingleton
>("librbd::ImageUpdateWatchers::thread_pool",
222 m_work_queue
= new ContextWQ("librbd::ImageUpdateWatchers::work_queue",
224 m_cct
->_conf
.get_val
<uint64_t>("rbd_op_thread_timeout")),
228 void destroy_work_queue() {
229 if (m_work_queue
== nullptr) {
232 m_work_queue
->drain();
237 class QuiesceWatchers
{
239 explicit QuiesceWatchers(CephContext
*cct
, asio::ContextWQ
* work_queue
)
241 m_work_queue(work_queue
),
242 m_lock(ceph::make_mutex(util::unique_lock_name(
243 "librbd::QuiesceWatchers::m_lock", this))) {
247 ceph_assert(m_pending_unregister
.empty());
248 ceph_assert(m_on_notify
== nullptr);
251 void register_watcher(QuiesceWatchCtx
*watcher
, uint64_t *handle
) {
252 ldout(m_cct
, 20) << "QuiesceWatchers::" << __func__
<< ": watcher="
255 std::lock_guard locker
{m_lock
};
257 *handle
= m_next_handle
++;
258 m_watchers
[*handle
] = watcher
;
261 void unregister_watcher(uint64_t handle
, Context
*on_finish
) {
264 std::lock_guard locker
{m_lock
};
265 auto it
= m_watchers
.find(handle
);
266 if (it
== m_watchers
.end()) {
269 if (m_on_notify
!= nullptr) {
270 ceph_assert(!m_pending_unregister
.count(handle
));
271 m_pending_unregister
[handle
] = on_finish
;
274 m_watchers
.erase(it
);
279 ldout(m_cct
, 20) << "QuiesceWatchers::" << __func__
280 << ": completing unregister " << handle
<< dendl
;
281 on_finish
->complete(r
);
285 void notify_quiesce(Context
*on_finish
) {
286 std::lock_guard locker
{m_lock
};
288 ldout(m_cct
, 20) << "QuiesceWatchers::" << __func__
<< ": queue" << dendl
;
289 m_pending_notify
.push_back(on_finish
);
293 notify(QUIESCE
, on_finish
);
296 void notify_unquiesce(Context
*on_finish
) {
297 std::lock_guard locker
{m_lock
};
299 notify(UNQUIESCE
, on_finish
);
302 void quiesce_complete(uint64_t handle
, int r
) {
303 Context
*on_notify
= nullptr;
305 std::lock_guard locker
{m_lock
};
306 ceph_assert(m_on_notify
!= nullptr);
307 ceph_assert(m_handle_quiesce_cnt
> 0);
309 m_handle_quiesce_cnt
--;
312 ldout(m_cct
, 10) << "QuiesceWatchers::" << __func__
<< ": watcher "
313 << handle
<< " failed" << dendl
;
314 m_failed_watchers
.insert(handle
);
318 if (m_handle_quiesce_cnt
> 0) {
322 std::swap(on_notify
, m_on_notify
);
326 on_notify
->complete(r
);
330 enum EventType
{QUIESCE
, UNQUIESCE
};
333 asio::ContextWQ
*m_work_queue
;
336 std::map
<uint64_t, QuiesceWatchCtx
*> m_watchers
;
337 uint64_t m_next_handle
= 0;
338 Context
*m_on_notify
= nullptr;
339 std::list
<Context
*> m_pending_notify
;
340 std::map
<uint64_t, Context
*> m_pending_unregister
;
341 uint64_t m_handle_quiesce_cnt
= 0;
342 std::set
<uint64_t> m_failed_watchers
;
343 bool m_blocked
= false;
346 void notify(EventType event_type
, Context
*on_finish
) {
347 ceph_assert(ceph_mutex_is_locked(m_lock
));
349 if (m_watchers
.empty()) {
350 m_work_queue
->queue(on_finish
);
354 ldout(m_cct
, 20) << "QuiesceWatchers::" << __func__
<< " event: "
355 << event_type
<< dendl
;
357 Context
*ctx
= nullptr;
358 if (event_type
== QUIESCE
) {
359 ceph_assert(!m_blocked
);
360 ceph_assert(m_handle_quiesce_cnt
== 0);
363 m_handle_quiesce_cnt
= m_watchers
.size();
364 m_failed_watchers
.clear();
367 ceph_assert(event_type
== UNQUIESCE
);
368 ceph_assert(m_blocked
);
370 ctx
= create_async_context_callback(
371 m_work_queue
, create_context_callback
<
372 QuiesceWatchers
, &QuiesceWatchers::handle_notify_unquiesce
>(this));
374 auto gather_ctx
= new C_Gather(m_cct
, ctx
);
376 ceph_assert(m_on_notify
== nullptr);
378 m_on_notify
= on_finish
;
380 for (auto &[handle
, watcher
] : m_watchers
) {
381 send_notify(handle
, watcher
, event_type
, gather_ctx
->new_sub());
384 gather_ctx
->activate();
387 void send_notify(uint64_t handle
, QuiesceWatchCtx
*watcher
,
388 EventType event_type
, Context
*on_finish
) {
389 auto ctx
= new LambdaContext(
390 [this, handle
, watcher
, event_type
, on_finish
](int) {
391 ldout(m_cct
, 20) << "QuiesceWatchers::" << __func__
<< ": handle="
392 << handle
<< ", event_type=" << event_type
<< dendl
;
393 switch (event_type
) {
395 watcher
->handle_quiesce();
399 std::lock_guard locker
{m_lock
};
401 if (m_failed_watchers
.count(handle
)) {
402 ldout(m_cct
, 20) << "QuiesceWatchers::" << __func__
403 << ": skip for failed watcher" << dendl
;
407 watcher
->handle_unquiesce();
410 ceph_abort_msgf("invalid event_type %d", event_type
);
413 on_finish
->complete(0);
416 m_work_queue
->queue(ctx
);
419 void handle_notify_unquiesce(int r
) {
420 ldout(m_cct
, 20) << "QuiesceWatchers::" << __func__
<< ": r=" << r
425 std::unique_lock locker
{m_lock
};
427 if (!m_pending_unregister
.empty()) {
428 std::map
<uint64_t, Context
*> pending_unregister
;
429 std::swap(pending_unregister
, m_pending_unregister
);
431 for (auto &it
: pending_unregister
) {
432 ldout(m_cct
, 20) << "QuiesceWatchers::" << __func__
433 << ": completing unregister " << it
.first
<< dendl
;
434 it
.second
->complete(0);
439 Context
*on_notify
= nullptr;
440 std::swap(on_notify
, m_on_notify
);
442 ceph_assert(m_blocked
);
445 if (!m_pending_notify
.empty()) {
446 auto on_finish
= m_pending_notify
.front();
447 m_pending_notify
.pop_front();
448 notify(QUIESCE
, on_finish
);
452 on_notify
->complete(0);
456 template <typename I
>
457 ImageState
<I
>::ImageState(I
*image_ctx
)
458 : m_image_ctx(image_ctx
), m_state(STATE_UNINITIALIZED
),
459 m_lock(ceph::make_mutex(util::unique_lock_name("librbd::ImageState::m_lock", this))),
460 m_last_refresh(0), m_refresh_seq(0),
461 m_update_watchers(new ImageUpdateWatchers(image_ctx
->cct
)),
462 m_quiesce_watchers(new QuiesceWatchers(
463 image_ctx
->cct
, image_ctx
->asio_engine
->get_work_queue())) {
466 template <typename I
>
467 ImageState
<I
>::~ImageState() {
468 ceph_assert(m_state
== STATE_UNINITIALIZED
|| m_state
== STATE_CLOSED
);
469 delete m_update_watchers
;
470 delete m_quiesce_watchers
;
473 template <typename I
>
474 int ImageState
<I
>::open(uint64_t flags
) {
482 template <typename I
>
483 void ImageState
<I
>::open(uint64_t flags
, Context
*on_finish
) {
484 CephContext
*cct
= m_image_ctx
->cct
;
485 ldout(cct
, 20) << __func__
<< dendl
;
488 ceph_assert(m_state
== STATE_UNINITIALIZED
);
489 m_open_flags
= flags
;
491 Action
action(ACTION_TYPE_OPEN
);
492 action
.refresh_seq
= m_refresh_seq
;
494 execute_action_unlock(action
, on_finish
);
497 template <typename I
>
498 int ImageState
<I
>::close() {
506 template <typename I
>
507 void ImageState
<I
>::close(Context
*on_finish
) {
508 CephContext
*cct
= m_image_ctx
->cct
;
509 ldout(cct
, 20) << __func__
<< dendl
;
512 ceph_assert(!is_closed());
514 Action
action(ACTION_TYPE_CLOSE
);
515 action
.refresh_seq
= m_refresh_seq
;
516 execute_action_unlock(action
, on_finish
);
519 template <typename I
>
520 void ImageState
<I
>::handle_update_notification() {
521 std::lock_guard locker
{m_lock
};
524 CephContext
*cct
= m_image_ctx
->cct
;
525 ldout(cct
, 20) << __func__
<< ": refresh_seq = " << m_refresh_seq
<< ", "
526 << "last_refresh = " << m_last_refresh
<< dendl
;
529 case STATE_UNINITIALIZED
:
533 ldout(cct
, 5) << "dropping update notification to watchers" << dendl
;
539 m_update_watchers
->notify();
542 template <typename I
>
543 bool ImageState
<I
>::is_refresh_required() const {
544 std::lock_guard locker
{m_lock
};
545 return (m_last_refresh
!= m_refresh_seq
|| find_pending_refresh() != nullptr);
548 template <typename I
>
549 int ImageState
<I
>::refresh() {
550 C_SaferCond refresh_ctx
;
551 refresh(&refresh_ctx
);
552 return refresh_ctx
.wait();
555 template <typename I
>
556 void ImageState
<I
>::refresh(Context
*on_finish
) {
557 CephContext
*cct
= m_image_ctx
->cct
;
558 ldout(cct
, 20) << __func__
<< dendl
;
563 on_finish
->complete(-ESHUTDOWN
);
567 Action
action(ACTION_TYPE_REFRESH
);
568 action
.refresh_seq
= m_refresh_seq
;
569 execute_action_unlock(action
, on_finish
);
572 template <typename I
>
573 int ImageState
<I
>::refresh_if_required() {
577 Action
action(ACTION_TYPE_REFRESH
);
578 action
.refresh_seq
= m_refresh_seq
;
580 auto refresh_action
= find_pending_refresh();
581 if (refresh_action
!= nullptr) {
582 // if a refresh is in-flight, delay until it is finished
583 action
= *refresh_action
;
584 } else if (m_last_refresh
== m_refresh_seq
) {
587 } else if (is_closed()) {
592 execute_action_unlock(action
, &ctx
);
598 template <typename I
>
599 const typename ImageState
<I
>::Action
*
600 ImageState
<I
>::find_pending_refresh() const {
601 ceph_assert(ceph_mutex_is_locked(m_lock
));
603 auto it
= std::find_if(m_actions_contexts
.rbegin(),
604 m_actions_contexts
.rend(),
605 [](const ActionContexts
& action_contexts
) {
606 return (action_contexts
.first
== ACTION_TYPE_REFRESH
);
608 if (it
!= m_actions_contexts
.rend()) {
614 template <typename I
>
615 void ImageState
<I
>::snap_set(uint64_t snap_id
, Context
*on_finish
) {
616 CephContext
*cct
= m_image_ctx
->cct
;
617 ldout(cct
, 20) << __func__
<< ": snap_id=" << snap_id
<< dendl
;
619 Action
action(ACTION_TYPE_SET_SNAP
);
620 action
.snap_id
= snap_id
;
623 execute_action_unlock(action
, on_finish
);
626 template <typename I
>
627 void ImageState
<I
>::prepare_lock(Context
*on_ready
) {
628 CephContext
*cct
= m_image_ctx
->cct
;
629 ldout(cct
, 10) << __func__
<< dendl
;
634 on_ready
->complete(-ESHUTDOWN
);
638 Action
action(ACTION_TYPE_LOCK
);
639 action
.on_ready
= on_ready
;
640 execute_action_unlock(action
, nullptr);
643 template <typename I
>
644 void ImageState
<I
>::handle_prepare_lock_complete() {
645 CephContext
*cct
= m_image_ctx
->cct
;
646 ldout(cct
, 10) << __func__
<< dendl
;
649 if (m_state
!= STATE_PREPARING_LOCK
) {
654 complete_action_unlock(STATE_OPEN
, 0);
657 template <typename I
>
658 int ImageState
<I
>::register_update_watcher(UpdateWatchCtx
*watcher
,
660 CephContext
*cct
= m_image_ctx
->cct
;
661 ldout(cct
, 20) << __func__
<< dendl
;
663 m_update_watchers
->register_watcher(watcher
, handle
);
665 ldout(cct
, 20) << __func__
<< ": handle=" << *handle
<< dendl
;
669 template <typename I
>
670 void ImageState
<I
>::unregister_update_watcher(uint64_t handle
,
671 Context
*on_finish
) {
672 CephContext
*cct
= m_image_ctx
->cct
;
673 ldout(cct
, 20) << __func__
<< ": handle=" << handle
<< dendl
;
675 m_update_watchers
->unregister_watcher(handle
, on_finish
);
678 template <typename I
>
679 int ImageState
<I
>::unregister_update_watcher(uint64_t handle
) {
681 unregister_update_watcher(handle
, &ctx
);
685 template <typename I
>
686 void ImageState
<I
>::flush_update_watchers(Context
*on_finish
) {
687 CephContext
*cct
= m_image_ctx
->cct
;
688 ldout(cct
, 20) << __func__
<< dendl
;
690 m_update_watchers
->flush(on_finish
);
693 template <typename I
>
694 void ImageState
<I
>::shut_down_update_watchers(Context
*on_finish
) {
695 CephContext
*cct
= m_image_ctx
->cct
;
696 ldout(cct
, 20) << __func__
<< dendl
;
698 m_update_watchers
->shut_down(on_finish
);
701 template <typename I
>
702 bool ImageState
<I
>::is_transition_state() const {
704 case STATE_UNINITIALIZED
:
710 case STATE_REFRESHING
:
711 case STATE_SETTING_SNAP
:
712 case STATE_PREPARING_LOCK
:
718 template <typename I
>
719 bool ImageState
<I
>::is_closed() const {
720 ceph_assert(ceph_mutex_is_locked(m_lock
));
722 return ((m_state
== STATE_CLOSED
) ||
723 (!m_actions_contexts
.empty() &&
724 m_actions_contexts
.back().first
.action_type
== ACTION_TYPE_CLOSE
));
727 template <typename I
>
728 void ImageState
<I
>::append_context(const Action
&action
, Context
*context
) {
729 ceph_assert(ceph_mutex_is_locked(m_lock
));
731 ActionContexts
*action_contexts
= nullptr;
732 for (auto &action_ctxs
: m_actions_contexts
) {
733 if (action
== action_ctxs
.first
) {
734 action_contexts
= &action_ctxs
;
739 if (action_contexts
== nullptr) {
740 m_actions_contexts
.push_back({action
, {}});
741 action_contexts
= &m_actions_contexts
.back();
744 if (context
!= nullptr) {
745 action_contexts
->second
.push_back(context
);
749 template <typename I
>
750 void ImageState
<I
>::execute_next_action_unlock() {
751 ceph_assert(ceph_mutex_is_locked(m_lock
));
752 ceph_assert(!m_actions_contexts
.empty());
753 switch (m_actions_contexts
.front().first
.action_type
) {
754 case ACTION_TYPE_OPEN
:
757 case ACTION_TYPE_CLOSE
:
760 case ACTION_TYPE_REFRESH
:
761 send_refresh_unlock();
763 case ACTION_TYPE_SET_SNAP
:
764 send_set_snap_unlock();
766 case ACTION_TYPE_LOCK
:
767 send_prepare_lock_unlock();
773 template <typename I
>
774 void ImageState
<I
>::execute_action_unlock(const Action
&action
,
775 Context
*on_finish
) {
776 ceph_assert(ceph_mutex_is_locked(m_lock
));
778 append_context(action
, on_finish
);
779 if (!is_transition_state()) {
780 execute_next_action_unlock();
786 template <typename I
>
787 void ImageState
<I
>::complete_action_unlock(State next_state
, int r
) {
788 ceph_assert(ceph_mutex_is_locked(m_lock
));
789 ceph_assert(!m_actions_contexts
.empty());
791 ActionContexts
action_contexts(std::move(m_actions_contexts
.front()));
792 m_actions_contexts
.pop_front();
794 m_state
= next_state
;
797 if (next_state
== STATE_CLOSED
||
798 (next_state
== STATE_UNINITIALIZED
&& r
< 0)) {
799 // the ImageCtx must be deleted outside the scope of its callback threads
800 auto ctx
= new LambdaContext(
801 [image_ctx
=m_image_ctx
, contexts
=std::move(action_contexts
.second
)]
804 for (auto ctx
: contexts
) {
808 TaskFinisherSingleton::get_singleton(m_image_ctx
->cct
).queue(ctx
, r
);
810 for (auto ctx
: action_contexts
.second
) {
811 if (next_state
== STATE_OPEN
) {
812 // we couldn't originally wrap the open callback w/ an async wrapper in
813 // case the image failed to open
814 ctx
= create_async_context_callback(*m_image_ctx
, ctx
);
820 if (!is_transition_state() && !m_actions_contexts
.empty()) {
821 execute_next_action_unlock();
828 template <typename I
>
829 void ImageState
<I
>::send_open_unlock() {
830 ceph_assert(ceph_mutex_is_locked(m_lock
));
831 CephContext
*cct
= m_image_ctx
->cct
;
832 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
834 m_state
= STATE_OPENING
;
836 Context
*ctx
= create_context_callback
<
837 ImageState
<I
>, &ImageState
<I
>::handle_open
>(this);
838 image::OpenRequest
<I
> *req
= image::OpenRequest
<I
>::create(
839 m_image_ctx
, m_open_flags
, ctx
);
845 template <typename I
>
846 void ImageState
<I
>::handle_open(int r
) {
847 CephContext
*cct
= m_image_ctx
->cct
;
848 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << r
<< dendl
;
850 if (r
< 0 && r
!= -ENOENT
) {
851 lderr(cct
) << "failed to open image: " << cpp_strerror(r
) << dendl
;
855 complete_action_unlock(r
< 0 ? STATE_UNINITIALIZED
: STATE_OPEN
, r
);
858 template <typename I
>
859 void ImageState
<I
>::send_close_unlock() {
860 ceph_assert(ceph_mutex_is_locked(m_lock
));
861 CephContext
*cct
= m_image_ctx
->cct
;
862 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
864 m_state
= STATE_CLOSING
;
866 Context
*ctx
= create_context_callback
<
867 ImageState
<I
>, &ImageState
<I
>::handle_close
>(this);
868 image::CloseRequest
<I
> *req
= image::CloseRequest
<I
>::create(
875 template <typename I
>
876 void ImageState
<I
>::handle_close(int r
) {
877 CephContext
*cct
= m_image_ctx
->cct
;
878 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << r
<< dendl
;
881 lderr(cct
) << "error occurred while closing image: " << cpp_strerror(r
)
886 complete_action_unlock(STATE_CLOSED
, r
);
889 template <typename I
>
890 void ImageState
<I
>::send_refresh_unlock() {
891 ceph_assert(ceph_mutex_is_locked(m_lock
));
892 CephContext
*cct
= m_image_ctx
->cct
;
893 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
895 m_state
= STATE_REFRESHING
;
896 ceph_assert(!m_actions_contexts
.empty());
897 auto &action_context
= m_actions_contexts
.front().first
;
898 ceph_assert(action_context
.action_type
== ACTION_TYPE_REFRESH
);
900 Context
*ctx
= create_async_context_callback(
901 *m_image_ctx
, create_context_callback
<
902 ImageState
<I
>, &ImageState
<I
>::handle_refresh
>(this));
903 image::RefreshRequest
<I
> *req
= image::RefreshRequest
<I
>::create(
904 *m_image_ctx
, false, false, ctx
);
910 template <typename I
>
911 void ImageState
<I
>::handle_refresh(int r
) {
912 CephContext
*cct
= m_image_ctx
->cct
;
913 ldout(cct
, 10) << this << " " << __func__
<< ": r=" << r
<< dendl
;
916 ceph_assert(!m_actions_contexts
.empty());
918 ActionContexts
&action_contexts(m_actions_contexts
.front());
919 ceph_assert(action_contexts
.first
.action_type
== ACTION_TYPE_REFRESH
);
920 ceph_assert(m_last_refresh
<= action_contexts
.first
.refresh_seq
);
922 if (r
== -ERESTART
) {
923 ldout(cct
, 5) << "incomplete refresh: not updating sequence" << dendl
;
926 m_last_refresh
= action_contexts
.first
.refresh_seq
;
929 complete_action_unlock(STATE_OPEN
, r
);
932 template <typename I
>
933 void ImageState
<I
>::send_set_snap_unlock() {
934 ceph_assert(ceph_mutex_is_locked(m_lock
));
936 m_state
= STATE_SETTING_SNAP
;
938 ceph_assert(!m_actions_contexts
.empty());
939 ActionContexts
&action_contexts(m_actions_contexts
.front());
940 ceph_assert(action_contexts
.first
.action_type
== ACTION_TYPE_SET_SNAP
);
942 CephContext
*cct
= m_image_ctx
->cct
;
943 ldout(cct
, 10) << this << " " << __func__
<< ": "
944 << "snap_id=" << action_contexts
.first
.snap_id
<< dendl
;
946 Context
*ctx
= create_async_context_callback(
947 *m_image_ctx
, create_context_callback
<
948 ImageState
<I
>, &ImageState
<I
>::handle_set_snap
>(this));
949 image::SetSnapRequest
<I
> *req
= image::SetSnapRequest
<I
>::create(
950 *m_image_ctx
, action_contexts
.first
.snap_id
, ctx
);
956 template <typename I
>
957 void ImageState
<I
>::handle_set_snap(int r
) {
958 CephContext
*cct
= m_image_ctx
->cct
;
959 ldout(cct
, 10) << this << " " << __func__
<< " r=" << r
<< dendl
;
961 if (r
< 0 && r
!= -ENOENT
) {
962 lderr(cct
) << "failed to set snapshot: " << cpp_strerror(r
) << dendl
;
966 complete_action_unlock(STATE_OPEN
, r
);
969 template <typename I
>
970 void ImageState
<I
>::send_prepare_lock_unlock() {
971 CephContext
*cct
= m_image_ctx
->cct
;
972 ldout(cct
, 10) << this << " " << __func__
<< dendl
;
974 ceph_assert(ceph_mutex_is_locked(m_lock
));
975 m_state
= STATE_PREPARING_LOCK
;
977 ceph_assert(!m_actions_contexts
.empty());
978 ActionContexts
&action_contexts(m_actions_contexts
.front());
979 ceph_assert(action_contexts
.first
.action_type
== ACTION_TYPE_LOCK
);
981 Context
*on_ready
= action_contexts
.first
.on_ready
;
984 if (on_ready
== nullptr) {
985 complete_action_unlock(STATE_OPEN
, 0);
989 // wake up the lock handler now that its safe to proceed
990 on_ready
->complete(0);
993 template <typename I
>
994 int ImageState
<I
>::register_quiesce_watcher(QuiesceWatchCtx
*watcher
,
996 CephContext
*cct
= m_image_ctx
->cct
;
997 ldout(cct
, 20) << __func__
<< dendl
;
999 m_quiesce_watchers
->register_watcher(watcher
, handle
);
1001 ldout(cct
, 20) << __func__
<< ": handle=" << *handle
<< dendl
;
1005 template <typename I
>
1006 int ImageState
<I
>::unregister_quiesce_watcher(uint64_t handle
) {
1007 CephContext
*cct
= m_image_ctx
->cct
;
1008 ldout(cct
, 20) << __func__
<< ": handle=" << handle
<< dendl
;
1011 m_quiesce_watchers
->unregister_watcher(handle
, &ctx
);
1015 template <typename I
>
1016 void ImageState
<I
>::notify_quiesce(Context
*on_finish
) {
1017 CephContext
*cct
= m_image_ctx
->cct
;
1018 ldout(cct
, 20) << __func__
<< dendl
;
1020 m_quiesce_watchers
->notify_quiesce(on_finish
);
1023 template <typename I
>
1024 void ImageState
<I
>::notify_unquiesce(Context
*on_finish
) {
1025 CephContext
*cct
= m_image_ctx
->cct
;
1026 ldout(cct
, 20) << __func__
<< dendl
;
1028 m_quiesce_watchers
->notify_unquiesce(on_finish
);
1031 template <typename I
>
1032 void ImageState
<I
>::quiesce_complete(uint64_t handle
, int r
) {
1033 CephContext
*cct
= m_image_ctx
->cct
;
1034 ldout(cct
, 20) << __func__
<< ": handle=" << handle
<< " r=" << r
<< dendl
;
1035 m_quiesce_watchers
->quiesce_complete(handle
, r
);
1038 } // namespace librbd
1040 template class librbd::ImageState
<librbd::ImageCtx
>;