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/Cond.h"
18 #include "common/WorkQueue.h"
19 #include "librbd/Utils.h"
21 #define dout_subsys ceph_subsys_rbd
23 #define dout_prefix *_dout << "librbd::ManagedLock: " << this << " " \
29 using namespace managed_lock
;
34 struct C_SendLockRequest
: public Context
{
36 explicit C_SendLockRequest(R
* request
) : request(request
) {
38 void finish(int r
) override
{
43 struct C_Tracked
: public Context
{
44 AsyncOpTracker
&tracker
;
46 C_Tracked(AsyncOpTracker
&tracker
, Context
*ctx
)
47 : tracker(tracker
), ctx(ctx
) {
50 ~C_Tracked() override
{
53 void finish(int r
) override
{
58 } // anonymous namespace
60 using librbd::util::create_context_callback
;
61 using librbd::util::unique_lock_name
;
62 using managed_lock::util::decode_lock_cookie
;
63 using managed_lock::util::encode_lock_cookie
;
66 ManagedLock
<I
>::ManagedLock(librados::IoCtx
&ioctx
, ContextWQ
*work_queue
,
67 const string
& oid
, Watcher
*watcher
, Mode mode
,
68 bool blacklist_on_break_lock
,
69 uint32_t blacklist_expire_seconds
)
70 : m_lock(ceph::make_mutex(unique_lock_name("librbd::ManagedLock<I>::m_lock", this))),
71 m_ioctx(ioctx
), m_cct(reinterpret_cast<CephContext
*>(ioctx
.cct())),
72 m_work_queue(work_queue
),
76 m_blacklist_on_break_lock(blacklist_on_break_lock
),
77 m_blacklist_expire_seconds(blacklist_expire_seconds
),
78 m_state(STATE_UNLOCKED
) {
82 ManagedLock
<I
>::~ManagedLock() {
83 std::lock_guard locker
{m_lock
};
84 ceph_assert(m_state
== STATE_SHUTDOWN
|| m_state
== STATE_UNLOCKED
||
85 m_state
== STATE_UNINITIALIZED
);
86 if (m_state
== STATE_UNINITIALIZED
) {
87 // never initialized -- ensure any in-flight ops are complete
88 // since we wouldn't expect shut_down to be invoked
90 m_async_op_tracker
.wait_for_ops(&ctx
);
93 ceph_assert(m_async_op_tracker
.empty());
97 bool ManagedLock
<I
>::is_lock_owner() const {
98 std::lock_guard locker
{m_lock
};
100 return is_lock_owner(m_lock
);
103 template <typename I
>
104 bool ManagedLock
<I
>::is_lock_owner(ceph::mutex
&lock
) const {
106 ceph_assert(ceph_mutex_is_locked(m_lock
));
112 case STATE_REACQUIRING
:
113 case STATE_PRE_SHUTTING_DOWN
:
114 case STATE_POST_ACQUIRING
:
115 case STATE_PRE_RELEASING
:
123 ldout(m_cct
, 20) << "=" << lock_owner
<< dendl
;
127 template <typename I
>
128 void ManagedLock
<I
>::shut_down(Context
*on_shut_down
) {
129 ldout(m_cct
, 10) << dendl
;
131 std::lock_guard locker
{m_lock
};
132 ceph_assert(!is_state_shutdown());
134 if (m_state
== STATE_WAITING_FOR_REGISTER
) {
135 // abort stalled acquire lock state
136 ldout(m_cct
, 10) << "woke up waiting (re)acquire" << dendl
;
137 Action active_action
= get_active_action();
138 ceph_assert(active_action
== ACTION_TRY_LOCK
||
139 active_action
== ACTION_ACQUIRE_LOCK
);
140 complete_active_action(STATE_UNLOCKED
, -ESHUTDOWN
);
143 execute_action(ACTION_SHUT_DOWN
, on_shut_down
);
146 template <typename I
>
147 void ManagedLock
<I
>::acquire_lock(Context
*on_acquired
) {
150 std::lock_guard locker
{m_lock
};
151 if (is_state_shutdown()) {
153 } else if (m_state
!= STATE_LOCKED
|| !m_actions_contexts
.empty()) {
154 ldout(m_cct
, 10) << dendl
;
155 execute_action(ACTION_ACQUIRE_LOCK
, on_acquired
);
160 if (on_acquired
!= nullptr) {
161 on_acquired
->complete(r
);
165 template <typename I
>
166 void ManagedLock
<I
>::try_acquire_lock(Context
*on_acquired
) {
169 std::lock_guard locker
{m_lock
};
170 if (is_state_shutdown()) {
172 } else if (m_state
!= STATE_LOCKED
|| !m_actions_contexts
.empty()) {
173 ldout(m_cct
, 10) << dendl
;
174 execute_action(ACTION_TRY_LOCK
, on_acquired
);
179 if (on_acquired
!= nullptr) {
180 on_acquired
->complete(r
);
184 template <typename I
>
185 void ManagedLock
<I
>::release_lock(Context
*on_released
) {
188 std::lock_guard locker
{m_lock
};
189 if (is_state_shutdown()) {
191 } else if (m_state
!= STATE_UNLOCKED
|| !m_actions_contexts
.empty()) {
192 ldout(m_cct
, 10) << dendl
;
193 execute_action(ACTION_RELEASE_LOCK
, on_released
);
198 if (on_released
!= nullptr) {
199 on_released
->complete(r
);
203 template <typename I
>
204 void ManagedLock
<I
>::reacquire_lock(Context
*on_reacquired
) {
206 std::lock_guard locker
{m_lock
};
208 if (m_state
== STATE_WAITING_FOR_REGISTER
) {
209 // restart the acquire lock process now that watch is valid
210 ldout(m_cct
, 10) << "woke up waiting (re)acquire" << dendl
;
211 Action active_action
= get_active_action();
212 ceph_assert(active_action
== ACTION_TRY_LOCK
||
213 active_action
== ACTION_ACQUIRE_LOCK
);
214 execute_next_action();
215 } else if (!is_state_shutdown() &&
216 (m_state
== STATE_LOCKED
||
217 m_state
== STATE_ACQUIRING
||
218 m_state
== STATE_POST_ACQUIRING
||
219 m_state
== STATE_WAITING_FOR_LOCK
)) {
220 // interlock the lock operation with other state ops
221 ldout(m_cct
, 10) << dendl
;
222 execute_action(ACTION_REACQUIRE_LOCK
, on_reacquired
);
227 // ignore request if shutdown or not in a locked-related state
228 if (on_reacquired
!= nullptr) {
229 on_reacquired
->complete(0);
233 template <typename I
>
234 void ManagedLock
<I
>::get_locker(managed_lock::Locker
*locker
,
235 Context
*on_finish
) {
236 ldout(m_cct
, 10) << dendl
;
240 std::lock_guard l
{m_lock
};
241 if (is_state_shutdown()) {
244 on_finish
= new C_Tracked(m_async_op_tracker
, on_finish
);
245 auto req
= managed_lock::GetLockerRequest
<I
>::create(
246 m_ioctx
, m_oid
, m_mode
== EXCLUSIVE
, locker
, on_finish
);
252 on_finish
->complete(r
);
255 template <typename I
>
256 void ManagedLock
<I
>::break_lock(const managed_lock::Locker
&locker
,
257 bool force_break_lock
, Context
*on_finish
) {
258 ldout(m_cct
, 10) << dendl
;
262 std::lock_guard l
{m_lock
};
263 if (is_state_shutdown()) {
265 } else if (is_lock_owner(m_lock
)) {
268 on_finish
= new C_Tracked(m_async_op_tracker
, on_finish
);
269 auto req
= managed_lock::BreakRequest
<I
>::create(
270 m_ioctx
, m_work_queue
, m_oid
, locker
, m_mode
== EXCLUSIVE
,
271 m_blacklist_on_break_lock
, m_blacklist_expire_seconds
, force_break_lock
,
278 on_finish
->complete(r
);
281 template <typename I
>
282 int ManagedLock
<I
>::assert_header_locked() {
283 ldout(m_cct
, 10) << dendl
;
285 librados::ObjectReadOperation op
;
287 std::lock_guard locker
{m_lock
};
288 rados::cls::lock::assert_locked(&op
, RBD_LOCK_NAME
,
289 (m_mode
== EXCLUSIVE
? LOCK_EXCLUSIVE
:
292 managed_lock::util::get_watcher_lock_tag());
295 int r
= m_ioctx
.operate(m_oid
, &op
, nullptr);
297 if (r
== -EBLACKLISTED
) {
298 ldout(m_cct
, 5) << "client is not lock owner -- client blacklisted"
300 } else if (r
== -ENOENT
) {
301 ldout(m_cct
, 5) << "client is not lock owner -- no lock detected"
303 } else if (r
== -EBUSY
) {
304 ldout(m_cct
, 5) << "client is not lock owner -- owned by different client"
307 lderr(m_cct
) << "failed to verify lock ownership: " << cpp_strerror(r
)
317 template <typename I
>
318 void ManagedLock
<I
>::shutdown_handler(int r
, Context
*on_finish
) {
319 on_finish
->complete(r
);
322 template <typename I
>
323 void ManagedLock
<I
>::pre_acquire_lock_handler(Context
*on_finish
) {
324 on_finish
->complete(0);
327 template <typename I
>
328 void ManagedLock
<I
>::post_acquire_lock_handler(int r
, Context
*on_finish
) {
329 on_finish
->complete(r
);
332 template <typename I
>
333 void ManagedLock
<I
>::pre_release_lock_handler(bool shutting_down
,
334 Context
*on_finish
) {
335 on_finish
->complete(0);
338 template <typename I
>
339 void ManagedLock
<I
>::post_release_lock_handler(bool shutting_down
, int r
,
340 Context
*on_finish
) {
341 on_finish
->complete(r
);
344 template <typename I
>
345 void ManagedLock
<I
>::post_reacquire_lock_handler(int r
, Context
*on_finish
) {
346 on_finish
->complete(r
);
349 template <typename I
>
350 bool ManagedLock
<I
>::is_transition_state() const {
352 case STATE_ACQUIRING
:
353 case STATE_WAITING_FOR_REGISTER
:
354 case STATE_REACQUIRING
:
355 case STATE_RELEASING
:
356 case STATE_PRE_SHUTTING_DOWN
:
357 case STATE_SHUTTING_DOWN
:
358 case STATE_INITIALIZING
:
359 case STATE_WAITING_FOR_LOCK
:
360 case STATE_POST_ACQUIRING
:
361 case STATE_PRE_RELEASING
:
366 case STATE_UNINITIALIZED
:
372 template <typename I
>
373 void ManagedLock
<I
>::append_context(Action action
, Context
*ctx
) {
374 ceph_assert(ceph_mutex_is_locked(m_lock
));
376 for (auto &action_ctxs
: m_actions_contexts
) {
377 if (action
== action_ctxs
.first
) {
378 if (ctx
!= nullptr) {
379 action_ctxs
.second
.push_back(ctx
);
386 if (ctx
!= nullptr) {
387 contexts
.push_back(ctx
);
389 m_actions_contexts
.push_back({action
, std::move(contexts
)});
392 template <typename I
>
393 void ManagedLock
<I
>::execute_action(Action action
, Context
*ctx
) {
394 ceph_assert(ceph_mutex_is_locked(m_lock
));
396 append_context(action
, ctx
);
397 if (!is_transition_state()) {
398 execute_next_action();
402 template <typename I
>
403 void ManagedLock
<I
>::execute_next_action() {
404 ceph_assert(ceph_mutex_is_locked(m_lock
));
405 ceph_assert(!m_actions_contexts
.empty());
406 switch (get_active_action()) {
407 case ACTION_ACQUIRE_LOCK
:
408 case ACTION_TRY_LOCK
:
411 case ACTION_REACQUIRE_LOCK
:
412 send_reacquire_lock();
414 case ACTION_RELEASE_LOCK
:
417 case ACTION_SHUT_DOWN
:
426 template <typename I
>
427 typename ManagedLock
<I
>::Action ManagedLock
<I
>::get_active_action() const {
428 ceph_assert(ceph_mutex_is_locked(m_lock
));
429 ceph_assert(!m_actions_contexts
.empty());
430 return m_actions_contexts
.front().first
;
433 template <typename I
>
434 void ManagedLock
<I
>::complete_active_action(State next_state
, int r
) {
435 ceph_assert(ceph_mutex_is_locked(m_lock
));
436 ceph_assert(!m_actions_contexts
.empty());
438 ActionContexts
action_contexts(std::move(m_actions_contexts
.front()));
439 m_actions_contexts
.pop_front();
440 m_state
= next_state
;
443 for (auto ctx
: action_contexts
.second
) {
448 if (!is_transition_state() && !m_actions_contexts
.empty()) {
449 execute_next_action();
453 template <typename I
>
454 bool ManagedLock
<I
>::is_state_shutdown() const {
455 ceph_assert(ceph_mutex_is_locked(m_lock
));
458 case STATE_PRE_SHUTTING_DOWN
:
459 case STATE_SHUTTING_DOWN
:
466 return (!m_actions_contexts
.empty() &&
467 m_actions_contexts
.back().first
== ACTION_SHUT_DOWN
);
470 template <typename I
>
471 void ManagedLock
<I
>::send_acquire_lock() {
472 ceph_assert(ceph_mutex_is_locked(m_lock
));
473 if (m_state
== STATE_LOCKED
) {
474 complete_active_action(STATE_LOCKED
, 0);
478 ldout(m_cct
, 10) << dendl
;
480 uint64_t watch_handle
= m_watcher
->get_watch_handle();
481 if (watch_handle
== 0) {
482 lderr(m_cct
) << "watcher not registered - delaying request" << dendl
;
483 m_state
= STATE_WAITING_FOR_REGISTER
;
485 // shut down might race w/ release/re-acquire of the lock
486 if (is_state_shutdown()) {
487 complete_active_action(STATE_UNLOCKED
, -ESHUTDOWN
);
492 m_state
= STATE_ACQUIRING
;
493 m_cookie
= encode_lock_cookie(watch_handle
);
495 m_work_queue
->queue(new LambdaContext([this](int r
) {
496 pre_acquire_lock_handler(create_context_callback
<
497 ManagedLock
<I
>, &ManagedLock
<I
>::handle_pre_acquire_lock
>(this));
501 template <typename I
>
502 void ManagedLock
<I
>::handle_pre_acquire_lock(int r
) {
503 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
506 handle_acquire_lock(r
);
510 using managed_lock::AcquireRequest
;
511 AcquireRequest
<I
>* req
= AcquireRequest
<I
>::create(
512 m_ioctx
, m_watcher
, m_work_queue
, m_oid
, m_cookie
, m_mode
== EXCLUSIVE
,
513 m_blacklist_on_break_lock
, m_blacklist_expire_seconds
,
514 create_context_callback
<
515 ManagedLock
<I
>, &ManagedLock
<I
>::handle_acquire_lock
>(this));
516 m_work_queue
->queue(new C_SendLockRequest
<AcquireRequest
<I
>>(req
), 0);
519 template <typename I
>
520 void ManagedLock
<I
>::handle_acquire_lock(int r
) {
521 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
523 if (r
== -EBUSY
|| r
== -EAGAIN
) {
524 ldout(m_cct
, 5) << "unable to acquire exclusive lock" << dendl
;
526 lderr(m_cct
) << "failed to acquire exclusive lock:" << cpp_strerror(r
)
529 ldout(m_cct
, 5) << "successfully acquired exclusive lock" << dendl
;
532 m_post_next_state
= (r
< 0 ? STATE_UNLOCKED
: STATE_LOCKED
);
534 m_work_queue
->queue(new LambdaContext([this, r
](int ret
) {
535 post_acquire_lock_handler(r
, create_context_callback
<
536 ManagedLock
<I
>, &ManagedLock
<I
>::handle_post_acquire_lock
>(this));
540 template <typename I
>
541 void ManagedLock
<I
>::handle_post_acquire_lock(int r
) {
542 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
544 std::lock_guard locker
{m_lock
};
546 if (r
< 0 && m_post_next_state
== STATE_LOCKED
) {
547 // release_lock without calling pre and post handlers
548 revert_to_unlock_state(r
);
549 } else if (r
!= -ECANCELED
) {
550 // fail the lock request
551 complete_active_action(m_post_next_state
, r
);
555 template <typename I
>
556 void ManagedLock
<I
>::revert_to_unlock_state(int r
) {
557 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
559 using managed_lock::ReleaseRequest
;
560 ReleaseRequest
<I
>* req
= ReleaseRequest
<I
>::create(m_ioctx
, m_watcher
,
561 m_work_queue
, m_oid
, m_cookie
,
562 new LambdaContext([this, r
](int ret
) {
563 std::lock_guard locker
{m_lock
};
564 ceph_assert(ret
== 0);
565 complete_active_action(STATE_UNLOCKED
, r
);
567 m_work_queue
->queue(new C_SendLockRequest
<ReleaseRequest
<I
>>(req
));
570 template <typename I
>
571 void ManagedLock
<I
>::send_reacquire_lock() {
572 ceph_assert(ceph_mutex_is_locked(m_lock
));
574 if (m_state
!= STATE_LOCKED
) {
575 complete_active_action(m_state
, 0);
579 ldout(m_cct
, 10) << dendl
;
580 m_state
= STATE_REACQUIRING
;
582 uint64_t watch_handle
= m_watcher
->get_watch_handle();
583 if (watch_handle
== 0) {
584 // watch (re)failed while recovering
585 lderr(m_cct
) << "aborting reacquire due to invalid watch handle"
588 // treat double-watch failure as a lost lock and invoke the
589 // release/acquire handlers
590 release_acquire_lock();
591 complete_active_action(STATE_LOCKED
, 0);
595 m_new_cookie
= encode_lock_cookie(watch_handle
);
596 if (m_cookie
== m_new_cookie
&& m_blacklist_on_break_lock
) {
597 ldout(m_cct
, 10) << "skipping reacquire since cookie still valid"
599 auto ctx
= create_context_callback
<
600 ManagedLock
, &ManagedLock
<I
>::handle_no_op_reacquire_lock
>(this);
601 post_reacquire_lock_handler(0, ctx
);
605 auto ctx
= create_context_callback
<
606 ManagedLock
, &ManagedLock
<I
>::handle_reacquire_lock
>(this);
607 ctx
= new LambdaContext([this, ctx
](int r
) {
608 post_reacquire_lock_handler(r
, ctx
);
611 using managed_lock::ReacquireRequest
;
612 ReacquireRequest
<I
>* req
= ReacquireRequest
<I
>::create(m_ioctx
, m_oid
,
613 m_cookie
, m_new_cookie
, m_mode
== EXCLUSIVE
, ctx
);
614 m_work_queue
->queue(new C_SendLockRequest
<ReacquireRequest
<I
>>(req
));
617 template <typename I
>
618 void ManagedLock
<I
>::handle_reacquire_lock(int r
) {
619 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
621 std::lock_guard locker
{m_lock
};
622 ceph_assert(m_state
== STATE_REACQUIRING
);
625 if (r
== -EOPNOTSUPP
) {
626 ldout(m_cct
, 10) << "updating lock is not supported" << dendl
;
628 lderr(m_cct
) << "failed to update lock cookie: " << cpp_strerror(r
)
632 release_acquire_lock();
634 m_cookie
= m_new_cookie
;
637 complete_active_action(STATE_LOCKED
, 0);
640 template <typename I
>
641 void ManagedLock
<I
>::handle_no_op_reacquire_lock(int r
) {
642 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
643 ceph_assert(m_state
== STATE_REACQUIRING
);
645 complete_active_action(STATE_LOCKED
, 0);
648 template <typename I
>
649 void ManagedLock
<I
>::release_acquire_lock() {
650 assert(ceph_mutex_is_locked(m_lock
));
652 if (!is_state_shutdown()) {
653 // queue a release and re-acquire of the lock since cookie cannot
654 // be updated on older OSDs
655 execute_action(ACTION_RELEASE_LOCK
, nullptr);
657 ceph_assert(!m_actions_contexts
.empty());
658 ActionContexts
&action_contexts(m_actions_contexts
.front());
660 // reacquire completes when the request lock completes
662 std::swap(contexts
, action_contexts
.second
);
663 if (contexts
.empty()) {
664 execute_action(ACTION_ACQUIRE_LOCK
, nullptr);
666 for (auto ctx
: contexts
) {
667 execute_action(ACTION_ACQUIRE_LOCK
, ctx
);
673 template <typename I
>
674 void ManagedLock
<I
>::send_release_lock() {
675 ceph_assert(ceph_mutex_is_locked(m_lock
));
676 if (m_state
== STATE_UNLOCKED
) {
677 complete_active_action(STATE_UNLOCKED
, 0);
681 ldout(m_cct
, 10) << dendl
;
682 m_state
= STATE_PRE_RELEASING
;
684 m_work_queue
->queue(new LambdaContext([this](int r
) {
685 pre_release_lock_handler(false, create_context_callback
<
686 ManagedLock
<I
>, &ManagedLock
<I
>::handle_pre_release_lock
>(this));
690 template <typename I
>
691 void ManagedLock
<I
>::handle_pre_release_lock(int r
) {
692 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
695 std::lock_guard locker
{m_lock
};
696 ceph_assert(m_state
== STATE_PRE_RELEASING
);
697 m_state
= STATE_RELEASING
;
701 handle_release_lock(r
);
705 using managed_lock::ReleaseRequest
;
706 ReleaseRequest
<I
>* req
= ReleaseRequest
<I
>::create(m_ioctx
, m_watcher
,
707 m_work_queue
, m_oid
, m_cookie
,
708 create_context_callback
<
709 ManagedLock
<I
>, &ManagedLock
<I
>::handle_release_lock
>(this));
710 m_work_queue
->queue(new C_SendLockRequest
<ReleaseRequest
<I
>>(req
), 0);
713 template <typename I
>
714 void ManagedLock
<I
>::handle_release_lock(int r
) {
715 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
717 std::lock_guard locker
{m_lock
};
718 ceph_assert(m_state
== STATE_RELEASING
);
720 if (r
>= 0 || r
== -EBLACKLISTED
|| r
== -ENOENT
) {
722 m_post_next_state
= STATE_UNLOCKED
;
724 m_post_next_state
= STATE_LOCKED
;
727 m_work_queue
->queue(new LambdaContext([this, r
](int ret
) {
728 post_release_lock_handler(false, r
, create_context_callback
<
729 ManagedLock
<I
>, &ManagedLock
<I
>::handle_post_release_lock
>(this));
733 template <typename I
>
734 void ManagedLock
<I
>::handle_post_release_lock(int r
) {
735 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
737 std::lock_guard locker
{m_lock
};
738 complete_active_action(m_post_next_state
, r
);
741 template <typename I
>
742 void ManagedLock
<I
>::send_shutdown() {
743 ldout(m_cct
, 10) << dendl
;
744 ceph_assert(ceph_mutex_is_locked(m_lock
));
745 if (m_state
== STATE_UNLOCKED
) {
746 m_state
= STATE_SHUTTING_DOWN
;
747 m_work_queue
->queue(new LambdaContext([this](int r
) {
748 shutdown_handler(r
, create_context_callback
<
749 ManagedLock
<I
>, &ManagedLock
<I
>::handle_shutdown
>(this));
754 ceph_assert(m_state
== STATE_LOCKED
);
755 m_state
= STATE_PRE_SHUTTING_DOWN
;
758 m_work_queue
->queue(new C_ShutDownRelease(this), 0);
762 template <typename I
>
763 void ManagedLock
<I
>::handle_shutdown(int r
) {
764 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
766 wait_for_tracked_ops(r
);
769 template <typename I
>
770 void ManagedLock
<I
>::send_shutdown_release() {
771 ldout(m_cct
, 10) << dendl
;
773 std::lock_guard locker
{m_lock
};
775 m_work_queue
->queue(new LambdaContext([this](int r
) {
776 pre_release_lock_handler(true, create_context_callback
<
777 ManagedLock
<I
>, &ManagedLock
<I
>::handle_shutdown_pre_release
>(this));
781 template <typename I
>
782 void ManagedLock
<I
>::handle_shutdown_pre_release(int r
) {
783 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
787 std::lock_guard locker
{m_lock
};
790 ceph_assert(m_state
== STATE_PRE_SHUTTING_DOWN
);
791 m_state
= STATE_SHUTTING_DOWN
;
794 using managed_lock::ReleaseRequest
;
795 ReleaseRequest
<I
>* req
= ReleaseRequest
<I
>::create(m_ioctx
, m_watcher
,
796 m_work_queue
, m_oid
, cookie
,
797 new LambdaContext([this, r
](int l
) {
798 int rst
= r
< 0 ? r
: l
;
799 post_release_lock_handler(true, rst
, create_context_callback
<
800 ManagedLock
<I
>, &ManagedLock
<I
>::handle_shutdown_post_release
>(this));
806 template <typename I
>
807 void ManagedLock
<I
>::handle_shutdown_post_release(int r
) {
808 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
810 wait_for_tracked_ops(r
);
813 template <typename I
>
814 void ManagedLock
<I
>::wait_for_tracked_ops(int r
) {
815 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
817 Context
*ctx
= new LambdaContext([this, r
](int ret
) {
818 complete_shutdown(r
);
821 m_async_op_tracker
.wait_for_ops(ctx
);
824 template <typename I
>
825 void ManagedLock
<I
>::complete_shutdown(int r
) {
826 ldout(m_cct
, 10) << "r=" << r
<< dendl
;
829 lderr(m_cct
) << "failed to shut down lock: " << cpp_strerror(r
)
833 ActionContexts action_contexts
;
835 std::lock_guard locker
{m_lock
};
836 ceph_assert(ceph_mutex_is_locked(m_lock
));
837 ceph_assert(m_actions_contexts
.size() == 1);
839 action_contexts
= std::move(m_actions_contexts
.front());
840 m_actions_contexts
.pop_front();
841 m_state
= STATE_SHUTDOWN
;
844 // expect to be destroyed after firing callback
845 for (auto ctx
: action_contexts
.second
) {
850 } // namespace librbd
852 template class librbd::ManagedLock
<librbd::ImageCtx
>;