1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/ManagedLock.h"
5 #include "librbd/managed_lock/AcquireRequest.h"
6 #include "librbd/managed_lock/BreakRequest.h"
7 #include "librbd/managed_lock/GetLockerRequest.h"
8 #include "librbd/managed_lock/ReleaseRequest.h"
9 #include "librbd/managed_lock/ReacquireRequest.h"
10 #include "librbd/managed_lock/Types.h"
11 #include "librbd/managed_lock/Utils.h"
12 #include "librbd/Watcher.h"
13 #include "librbd/ImageCtx.h"
14 #include "cls/lock/cls_lock_client.h"
15 #include "common/dout.h"
16 #include "common/errno.h"
17 #include "common/WorkQueue.h"
18 #include "librbd/Utils.h"
20 #define dout_subsys ceph_subsys_rbd
22 #define dout_prefix *_dout << "librbd::ManagedLock: " << this << " " \
28 using namespace managed_lock
;
33 struct C_SendLockRequest
: public Context
{
35 explicit C_SendLockRequest(R
* request
) : request(request
) {
37 void finish(int r
) override
{
42 struct C_Tracked
: public Context
{
43 AsyncOpTracker
&tracker
;
45 C_Tracked(AsyncOpTracker
&tracker
, Context
*ctx
)
46 : tracker(tracker
), ctx(ctx
) {
49 ~C_Tracked() override
{
52 void finish(int r
) override
{
57 } // anonymous namespace
59 using librbd::util::create_context_callback
;
60 using librbd::util::unique_lock_name
;
61 using managed_lock::util::decode_lock_cookie
;
62 using managed_lock::util::encode_lock_cookie
;
65 ManagedLock
<I
>::ManagedLock(librados::IoCtx
&ioctx
, ContextWQ
*work_queue
,
66 const string
& oid
, Watcher
*watcher
, Mode mode
,
67 bool blacklist_on_break_lock
,
68 uint32_t blacklist_expire_seconds
)
69 : m_lock(unique_lock_name("librbd::ManagedLock<I>::m_lock", this)),
70 m_ioctx(ioctx
), m_cct(reinterpret_cast<CephContext
*>(ioctx
.cct())),
71 m_work_queue(work_queue
),
75 m_blacklist_on_break_lock(blacklist_on_break_lock
),
76 m_blacklist_expire_seconds(blacklist_expire_seconds
),
77 m_state(STATE_UNLOCKED
) {
81 ManagedLock
<I
>::~ManagedLock() {
82 Mutex::Locker
locker(m_lock
);
83 assert(m_state
== STATE_SHUTDOWN
|| m_state
== STATE_UNLOCKED
||
84 m_state
== STATE_UNINITIALIZED
);
85 if (m_state
== STATE_UNINITIALIZED
) {
86 // never initialized -- ensure any in-flight ops are complete
87 // since we wouldn't expect shut_down to be invoked
89 m_async_op_tracker
.wait_for_ops(&ctx
);
92 assert(m_async_op_tracker
.empty());
96 bool ManagedLock
<I
>::is_lock_owner() const {
97 Mutex::Locker
locker(m_lock
);
99 return is_lock_owner(m_lock
);
102 template <typename I
>
103 bool ManagedLock
<I
>::is_lock_owner(Mutex
&lock
) const {
105 assert(m_lock
.is_locked());
111 case STATE_REACQUIRING
:
112 case STATE_PRE_SHUTTING_DOWN
:
113 case STATE_POST_ACQUIRING
:
114 case STATE_PRE_RELEASING
:
122 ldout(m_cct
, 20) << "=" << lock_owner
<< dendl
;
126 template <typename I
>
127 void ManagedLock
<I
>::shut_down(Context
*on_shut_down
) {
128 ldout(m_cct
, 10) << dendl
;
130 Mutex::Locker
locker(m_lock
);
131 assert(!is_state_shutdown());
132 execute_action(ACTION_SHUT_DOWN
, on_shut_down
);
135 template <typename I
>
136 void ManagedLock
<I
>::acquire_lock(Context
*on_acquired
) {
139 Mutex::Locker
locker(m_lock
);
140 if (is_state_shutdown()) {
142 } else if (m_state
!= STATE_LOCKED
|| !m_actions_contexts
.empty()) {
143 ldout(m_cct
, 10) << dendl
;
144 execute_action(ACTION_ACQUIRE_LOCK
, on_acquired
);
149 if (on_acquired
!= nullptr) {
150 on_acquired
->complete(r
);
154 template <typename I
>
155 void ManagedLock
<I
>::try_acquire_lock(Context
*on_acquired
) {
158 Mutex::Locker
locker(m_lock
);
159 if (is_state_shutdown()) {
161 } else if (m_state
!= STATE_LOCKED
|| !m_actions_contexts
.empty()) {
162 ldout(m_cct
, 10) << dendl
;
163 execute_action(ACTION_TRY_LOCK
, on_acquired
);
168 if (on_acquired
!= nullptr) {
169 on_acquired
->complete(r
);
173 template <typename I
>
174 void ManagedLock
<I
>::release_lock(Context
*on_released
) {
177 Mutex::Locker
locker(m_lock
);
178 if (is_state_shutdown()) {
180 } else if (m_state
!= STATE_UNLOCKED
|| !m_actions_contexts
.empty()) {
181 ldout(m_cct
, 10) << dendl
;
182 execute_action(ACTION_RELEASE_LOCK
, on_released
);
187 if (on_released
!= nullptr) {
188 on_released
->complete(r
);
192 template <typename I
>
193 void ManagedLock
<I
>::reacquire_lock(Context
*on_reacquired
) {
195 Mutex::Locker
locker(m_lock
);
197 if (m_state
== STATE_WAITING_FOR_REGISTER
) {
198 // restart the acquire lock process now that watch is valid
199 ldout(m_cct
, 10) << ": " << "woke up waiting acquire" << dendl
;
200 Action active_action
= get_active_action();
201 assert(active_action
== ACTION_TRY_LOCK
||
202 active_action
== ACTION_ACQUIRE_LOCK
);
203 execute_next_action();
204 } else if (!is_state_shutdown() &&
205 (m_state
== STATE_LOCKED
||
206 m_state
== STATE_ACQUIRING
||
207 m_state
== STATE_POST_ACQUIRING
||
208 m_state
== STATE_WAITING_FOR_LOCK
)) {
209 // interlock the lock operation with other state ops
210 ldout(m_cct
, 10) << dendl
;
211 execute_action(ACTION_REACQUIRE_LOCK
, on_reacquired
);
216 // ignore request if shutdown or not in a locked-related state
217 if (on_reacquired
!= nullptr) {
218 on_reacquired
->complete(0);
222 template <typename I
>
223 void ManagedLock
<I
>::get_locker(managed_lock::Locker
*locker
,
224 Context
*on_finish
) {
225 ldout(m_cct
, 10) << dendl
;
229 Mutex::Locker
l(m_lock
);
230 if (is_state_shutdown()) {
233 on_finish
= new C_Tracked(m_async_op_tracker
, on_finish
);
234 auto req
= managed_lock::GetLockerRequest
<I
>::create(
235 m_ioctx
, m_oid
, m_mode
== EXCLUSIVE
, locker
, on_finish
);
241 on_finish
->complete(r
);
244 template <typename I
>
245 void ManagedLock
<I
>::break_lock(const managed_lock::Locker
&locker
,
246 bool force_break_lock
, Context
*on_finish
) {
247 ldout(m_cct
, 10) << dendl
;
251 Mutex::Locker
l(m_lock
);
252 if (is_state_shutdown()) {
254 } else if (is_lock_owner(m_lock
)) {
257 on_finish
= new C_Tracked(m_async_op_tracker
, on_finish
);
258 auto req
= managed_lock::BreakRequest
<I
>::create(
259 m_ioctx
, m_work_queue
, m_oid
, locker
, m_blacklist_on_break_lock
,
260 m_blacklist_expire_seconds
, force_break_lock
, on_finish
);
266 on_finish
->complete(r
);
269 template <typename I
>
270 int ManagedLock
<I
>::assert_header_locked() {
271 ldout(m_cct
, 10) << dendl
;
273 librados::ObjectReadOperation op
;
275 Mutex::Locker
locker(m_lock
);
276 rados::cls::lock::assert_locked(&op
, RBD_LOCK_NAME
,
277 (m_mode
== EXCLUSIVE
? LOCK_EXCLUSIVE
:
280 managed_lock::util::get_watcher_lock_tag());
283 int r
= m_ioctx
.operate(m_oid
, &op
, nullptr);
285 if (r
== -EBLACKLISTED
) {
286 ldout(m_cct
, 5) << "client is not lock owner -- client blacklisted"
288 } else if (r
== -ENOENT
) {
289 ldout(m_cct
, 5) << "client is not lock owner -- no lock detected"
291 } else if (r
== -EBUSY
) {
292 ldout(m_cct
, 5) << "client is not lock owner -- owned by different client"
295 lderr(m_cct
) << "failed to verify lock ownership: " << cpp_strerror(r
)
305 template <typename I
>
306 void ManagedLock
<I
>::shutdown_handler(int r
, Context
*on_finish
) {
307 on_finish
->complete(r
);
310 template <typename I
>
311 void ManagedLock
<I
>::pre_acquire_lock_handler(Context
*on_finish
) {
312 on_finish
->complete(0);
315 template <typename I
>
316 void ManagedLock
<I
>::post_acquire_lock_handler(int r
, Context
*on_finish
) {
317 on_finish
->complete(r
);
320 template <typename I
>
321 void ManagedLock
<I
>::pre_release_lock_handler(bool shutting_down
,
322 Context
*on_finish
) {
323 on_finish
->complete(0);
326 template <typename I
>
327 void ManagedLock
<I
>::post_release_lock_handler(bool shutting_down
, int r
,
328 Context
*on_finish
) {
329 on_finish
->complete(r
);
332 template <typename I
>
333 bool ManagedLock
<I
>::is_transition_state() const {
335 case STATE_ACQUIRING
:
336 case STATE_WAITING_FOR_REGISTER
:
337 case STATE_REACQUIRING
:
338 case STATE_RELEASING
:
339 case STATE_PRE_SHUTTING_DOWN
:
340 case STATE_SHUTTING_DOWN
:
341 case STATE_INITIALIZING
:
342 case STATE_WAITING_FOR_LOCK
:
343 case STATE_POST_ACQUIRING
:
344 case STATE_PRE_RELEASING
:
349 case STATE_UNINITIALIZED
:
355 template <typename I
>
356 void ManagedLock
<I
>::append_context(Action action
, Context
*ctx
) {
357 assert(m_lock
.is_locked());
359 for (auto &action_ctxs
: m_actions_contexts
) {
360 if (action
== action_ctxs
.first
) {
361 if (ctx
!= nullptr) {
362 action_ctxs
.second
.push_back(ctx
);
369 if (ctx
!= nullptr) {
370 contexts
.push_back(ctx
);
372 m_actions_contexts
.push_back({action
, std::move(contexts
)});
375 template <typename I
>
376 void ManagedLock
<I
>::execute_action(Action action
, Context
*ctx
) {
377 assert(m_lock
.is_locked());
379 append_context(action
, ctx
);
380 if (!is_transition_state()) {
381 execute_next_action();
385 template <typename I
>
386 void ManagedLock
<I
>::execute_next_action() {
387 assert(m_lock
.is_locked());
388 assert(!m_actions_contexts
.empty());
389 switch (get_active_action()) {
390 case ACTION_ACQUIRE_LOCK
:
391 case ACTION_TRY_LOCK
:
394 case ACTION_REACQUIRE_LOCK
:
395 send_reacquire_lock();
397 case ACTION_RELEASE_LOCK
:
400 case ACTION_SHUT_DOWN
:
409 template <typename I
>
410 typename ManagedLock
<I
>::Action ManagedLock
<I
>::get_active_action() const {
411 assert(m_lock
.is_locked());
412 assert(!m_actions_contexts
.empty());
413 return m_actions_contexts
.front().first
;
416 template <typename I
>
417 void ManagedLock
<I
>::complete_active_action(State next_state
, int r
) {
418 assert(m_lock
.is_locked());
419 assert(!m_actions_contexts
.empty());
421 ActionContexts
action_contexts(std::move(m_actions_contexts
.front()));
422 m_actions_contexts
.pop_front();
423 m_state
= next_state
;
426 for (auto ctx
: action_contexts
.second
) {
431 if (!is_transition_state() && !m_actions_contexts
.empty()) {
432 execute_next_action();
436 template <typename I
>
437 bool ManagedLock
<I
>::is_state_shutdown() const {
438 assert(m_lock
.is_locked());
440 return ((m_state
== STATE_SHUTDOWN
) ||
441 (!m_actions_contexts
.empty() &&
442 m_actions_contexts
.back().first
== ACTION_SHUT_DOWN
));
445 template <typename I
>
446 void ManagedLock
<I
>::send_acquire_lock() {
447 assert(m_lock
.is_locked());
448 if (m_state
== STATE_LOCKED
) {
449 complete_active_action(STATE_LOCKED
, 0);
453 ldout(m_cct
, 10) << dendl
;
454 m_state
= STATE_ACQUIRING
;
456 uint64_t watch_handle
= m_watcher
->get_watch_handle();
457 if (watch_handle
== 0) {
458 lderr(m_cct
) << "watcher not registered - delaying request" << dendl
;
459 m_state
= STATE_WAITING_FOR_REGISTER
;
462 m_cookie
= encode_lock_cookie(watch_handle
);
464 m_work_queue
->queue(new FunctionContext([this](int r
) {
465 pre_acquire_lock_handler(create_context_callback
<
466 ManagedLock
<I
>, &ManagedLock
<I
>::handle_pre_acquire_lock
>(this));
470 template <typename I
>
471 void ManagedLock
<I
>::handle_pre_acquire_lock(int r
) {
472 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
475 handle_acquire_lock(r
);
479 using managed_lock::AcquireRequest
;
480 AcquireRequest
<I
>* req
= AcquireRequest
<I
>::create(
481 m_ioctx
, m_watcher
, m_work_queue
, m_oid
, m_cookie
, m_mode
== EXCLUSIVE
,
482 m_blacklist_on_break_lock
, m_blacklist_expire_seconds
,
483 create_context_callback
<
484 ManagedLock
<I
>, &ManagedLock
<I
>::handle_acquire_lock
>(this));
485 m_work_queue
->queue(new C_SendLockRequest
<AcquireRequest
<I
>>(req
), 0);
488 template <typename I
>
489 void ManagedLock
<I
>::handle_acquire_lock(int r
) {
490 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
492 if (r
== -EBUSY
|| r
== -EAGAIN
) {
493 ldout(m_cct
, 5) << ": unable to acquire exclusive lock" << dendl
;
495 lderr(m_cct
) << ": failed to acquire exclusive lock:" << cpp_strerror(r
)
498 ldout(m_cct
, 5) << ": successfully acquired exclusive lock" << dendl
;
501 m_post_next_state
= (r
< 0 ? STATE_UNLOCKED
: STATE_LOCKED
);
503 m_work_queue
->queue(new FunctionContext([this, r
](int ret
) {
504 post_acquire_lock_handler(r
, create_context_callback
<
505 ManagedLock
<I
>, &ManagedLock
<I
>::handle_post_acquire_lock
>(this));
509 template <typename I
>
510 void ManagedLock
<I
>::handle_post_acquire_lock(int r
) {
511 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
513 Mutex::Locker
locker(m_lock
);
515 if (r
< 0 && m_post_next_state
== STATE_LOCKED
) {
516 // release_lock without calling pre and post handlers
517 revert_to_unlock_state(r
);
518 } else if (r
!= -ECANCELED
) {
519 // fail the lock request
520 complete_active_action(m_post_next_state
, r
);
524 template <typename I
>
525 void ManagedLock
<I
>::revert_to_unlock_state(int r
) {
526 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
528 using managed_lock::ReleaseRequest
;
529 ReleaseRequest
<I
>* req
= ReleaseRequest
<I
>::create(m_ioctx
, m_watcher
,
530 m_work_queue
, m_oid
, m_cookie
,
531 new FunctionContext([this, r
](int ret
) {
532 Mutex::Locker
locker(m_lock
);
534 complete_active_action(STATE_UNLOCKED
, r
);
536 m_work_queue
->queue(new C_SendLockRequest
<ReleaseRequest
<I
>>(req
));
539 template <typename I
>
540 void ManagedLock
<I
>::send_reacquire_lock() {
541 assert(m_lock
.is_locked());
543 if (m_state
!= STATE_LOCKED
) {
544 complete_active_action(m_state
, 0);
548 uint64_t watch_handle
= m_watcher
->get_watch_handle();
549 if (watch_handle
== 0) {
550 // watch (re)failed while recovering
551 lderr(m_cct
) << ": aborting reacquire due to invalid watch handle"
553 complete_active_action(STATE_LOCKED
, 0);
557 m_new_cookie
= encode_lock_cookie(watch_handle
);
558 if (m_cookie
== m_new_cookie
) {
559 ldout(m_cct
, 10) << ": skipping reacquire since cookie still valid"
561 complete_active_action(STATE_LOCKED
, 0);
565 ldout(m_cct
, 10) << dendl
;
566 m_state
= STATE_REACQUIRING
;
568 using managed_lock::ReacquireRequest
;
569 ReacquireRequest
<I
>* req
= ReacquireRequest
<I
>::create(m_ioctx
, m_oid
,
570 m_cookie
, m_new_cookie
, m_mode
== EXCLUSIVE
,
571 create_context_callback
<
572 ManagedLock
, &ManagedLock
<I
>::handle_reacquire_lock
>(this));
573 m_work_queue
->queue(new C_SendLockRequest
<ReacquireRequest
<I
>>(req
));
576 template <typename I
>
577 void ManagedLock
<I
>::handle_reacquire_lock(int r
) {
578 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
580 Mutex::Locker
locker(m_lock
);
581 assert(m_state
== STATE_REACQUIRING
);
584 if (r
== -EOPNOTSUPP
) {
585 ldout(m_cct
, 10) << ": updating lock is not supported" << dendl
;
587 lderr(m_cct
) << ": failed to update lock cookie: " << cpp_strerror(r
)
591 if (!is_state_shutdown()) {
592 // queue a release and re-acquire of the lock since cookie cannot
593 // be updated on older OSDs
594 execute_action(ACTION_RELEASE_LOCK
, nullptr);
596 assert(!m_actions_contexts
.empty());
597 ActionContexts
&action_contexts(m_actions_contexts
.front());
599 // reacquire completes when the request lock completes
601 std::swap(contexts
, action_contexts
.second
);
602 if (contexts
.empty()) {
603 execute_action(ACTION_ACQUIRE_LOCK
, nullptr);
605 for (auto ctx
: contexts
) {
606 ctx
= new FunctionContext([ctx
, r
](int acquire_ret_val
) {
607 if (acquire_ret_val
>= 0) {
610 ctx
->complete(acquire_ret_val
);
612 execute_action(ACTION_ACQUIRE_LOCK
, ctx
);
617 m_cookie
= m_new_cookie
;
620 complete_active_action(STATE_LOCKED
, r
);
623 template <typename I
>
624 void ManagedLock
<I
>::send_release_lock() {
625 assert(m_lock
.is_locked());
626 if (m_state
== STATE_UNLOCKED
) {
627 complete_active_action(STATE_UNLOCKED
, 0);
631 ldout(m_cct
, 10) << dendl
;
632 m_state
= STATE_PRE_RELEASING
;
634 m_work_queue
->queue(new FunctionContext([this](int r
) {
635 pre_release_lock_handler(false, create_context_callback
<
636 ManagedLock
<I
>, &ManagedLock
<I
>::handle_pre_release_lock
>(this));
640 template <typename I
>
641 void ManagedLock
<I
>::handle_pre_release_lock(int r
) {
642 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
645 Mutex::Locker
locker(m_lock
);
646 assert(m_state
== STATE_PRE_RELEASING
);
647 m_state
= STATE_RELEASING
;
651 handle_release_lock(r
);
655 using managed_lock::ReleaseRequest
;
656 ReleaseRequest
<I
>* req
= ReleaseRequest
<I
>::create(m_ioctx
, m_watcher
,
657 m_work_queue
, m_oid
, m_cookie
,
658 create_context_callback
<
659 ManagedLock
<I
>, &ManagedLock
<I
>::handle_release_lock
>(this));
660 m_work_queue
->queue(new C_SendLockRequest
<ReleaseRequest
<I
>>(req
), 0);
663 template <typename I
>
664 void ManagedLock
<I
>::handle_release_lock(int r
) {
665 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
667 Mutex::Locker
locker(m_lock
);
668 assert(m_state
== STATE_RELEASING
);
674 m_post_next_state
= r
< 0 ? STATE_LOCKED
: STATE_UNLOCKED
;
676 m_work_queue
->queue(new FunctionContext([this, r
](int ret
) {
677 post_release_lock_handler(false, r
, create_context_callback
<
678 ManagedLock
<I
>, &ManagedLock
<I
>::handle_post_release_lock
>(this));
682 template <typename I
>
683 void ManagedLock
<I
>::handle_post_release_lock(int r
) {
684 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
686 Mutex::Locker
locker(m_lock
);
687 complete_active_action(m_post_next_state
, r
);
690 template <typename I
>
691 void ManagedLock
<I
>::send_shutdown() {
692 ldout(m_cct
, 10) << dendl
;
693 assert(m_lock
.is_locked());
694 if (m_state
== STATE_UNLOCKED
) {
695 m_state
= STATE_SHUTTING_DOWN
;
696 m_work_queue
->queue(new FunctionContext([this](int r
) {
697 shutdown_handler(r
, create_context_callback
<
698 ManagedLock
<I
>, &ManagedLock
<I
>::handle_shutdown
>(this));
703 assert(m_state
== STATE_LOCKED
);
704 m_state
= STATE_PRE_SHUTTING_DOWN
;
707 m_work_queue
->queue(new C_ShutDownRelease(this), 0);
711 template <typename I
>
712 void ManagedLock
<I
>::handle_shutdown(int r
) {
713 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
715 wait_for_tracked_ops(r
);
718 template <typename I
>
719 void ManagedLock
<I
>::send_shutdown_release() {
720 ldout(m_cct
, 10) << dendl
;
722 Mutex::Locker
locker(m_lock
);
724 m_work_queue
->queue(new FunctionContext([this](int r
) {
725 pre_release_lock_handler(true, create_context_callback
<
726 ManagedLock
<I
>, &ManagedLock
<I
>::handle_shutdown_pre_release
>(this));
730 template <typename I
>
731 void ManagedLock
<I
>::handle_shutdown_pre_release(int r
) {
732 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
736 Mutex::Locker
locker(m_lock
);
739 assert(m_state
== STATE_PRE_SHUTTING_DOWN
);
740 m_state
= STATE_SHUTTING_DOWN
;
743 using managed_lock::ReleaseRequest
;
744 ReleaseRequest
<I
>* req
= ReleaseRequest
<I
>::create(m_ioctx
, m_watcher
,
745 m_work_queue
, m_oid
, cookie
,
746 new FunctionContext([this](int r
) {
747 post_release_lock_handler(true, r
, create_context_callback
<
748 ManagedLock
<I
>, &ManagedLock
<I
>::handle_shutdown_post_release
>(this));
754 template <typename I
>
755 void ManagedLock
<I
>::handle_shutdown_post_release(int r
) {
756 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
758 wait_for_tracked_ops(r
);
761 template <typename I
>
762 void ManagedLock
<I
>::wait_for_tracked_ops(int r
) {
763 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
765 Context
*ctx
= new FunctionContext([this, r
](int ret
) {
766 complete_shutdown(r
);
769 m_async_op_tracker
.wait_for_ops(ctx
);
772 template <typename I
>
773 void ManagedLock
<I
>::complete_shutdown(int r
) {
774 ldout(m_cct
, 10) << ": r=" << r
<< dendl
;
777 lderr(m_cct
) << "failed to shut down lock: " << cpp_strerror(r
)
781 ActionContexts action_contexts
;
783 Mutex::Locker
locker(m_lock
);
784 assert(m_lock
.is_locked());
785 assert(m_actions_contexts
.size() == 1);
787 action_contexts
= std::move(m_actions_contexts
.front());
788 m_actions_contexts
.pop_front();
789 m_state
= STATE_SHUTDOWN
;
792 // expect to be destroyed after firing callback
793 for (auto ctx
: action_contexts
.second
) {
798 } // namespace librbd
800 template class librbd::ManagedLock
<librbd::ImageCtx
>;