]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/ManagedLock.cc
update sources to v12.1.0
[ceph.git] / ceph / src / librbd / ManagedLock.cc
CommitLineData
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/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"
19
20#define dout_subsys ceph_subsys_rbd
21#undef dout_prefix
22#define dout_prefix *_dout << "librbd::ManagedLock: " << this << " " \
23 << __func__
24
25namespace librbd {
26
27using std::string;
28using namespace managed_lock;
29
30namespace {
31
32template <typename R>
33struct C_SendLockRequest : public Context {
34 R* request;
35 explicit C_SendLockRequest(R* request) : request(request) {
36 }
37 void finish(int r) override {
38 request->send();
39 }
40};
41
42struct C_Tracked : public Context {
43 AsyncOpTracker &tracker;
44 Context *ctx;
45 C_Tracked(AsyncOpTracker &tracker, Context *ctx)
46 : tracker(tracker), ctx(ctx) {
47 tracker.start_op();
48 }
49 ~C_Tracked() override {
50 tracker.finish_op();
51 }
52 void finish(int r) override {
53 ctx->complete(r);
54 }
55};
56
57} // anonymous namespace
58
59using librbd::util::create_context_callback;
60using librbd::util::unique_lock_name;
61using managed_lock::util::decode_lock_cookie;
62using managed_lock::util::encode_lock_cookie;
63
64template <typename I>
65ManagedLock<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),
72 m_oid(oid),
73 m_watcher(watcher),
74 m_mode(mode),
75 m_blacklist_on_break_lock(blacklist_on_break_lock),
76 m_blacklist_expire_seconds(blacklist_expire_seconds),
77 m_state(STATE_UNLOCKED) {
78}
79
80template <typename I>
81ManagedLock<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
88 C_SaferCond ctx;
89 m_async_op_tracker.wait_for_ops(&ctx);
90 ctx.wait();
91 }
92 assert(m_async_op_tracker.empty());
93}
94
95template <typename I>
96bool ManagedLock<I>::is_lock_owner() const {
97 Mutex::Locker locker(m_lock);
98
99 return is_lock_owner(m_lock);
100}
101
102template <typename I>
103bool ManagedLock<I>::is_lock_owner(Mutex &lock) const {
104
105 assert(m_lock.is_locked());
106
107 bool lock_owner;
108
109 switch (m_state) {
110 case STATE_LOCKED:
111 case STATE_REACQUIRING:
112 case STATE_PRE_SHUTTING_DOWN:
113 case STATE_POST_ACQUIRING:
114 case STATE_PRE_RELEASING:
115 lock_owner = true;
116 break;
117 default:
118 lock_owner = false;
119 break;
120 }
121
122 ldout(m_cct, 20) << "=" << lock_owner << dendl;
123 return lock_owner;
124}
125
126template <typename I>
127void ManagedLock<I>::shut_down(Context *on_shut_down) {
128 ldout(m_cct, 10) << dendl;
129
130 Mutex::Locker locker(m_lock);
131 assert(!is_state_shutdown());
132 execute_action(ACTION_SHUT_DOWN, on_shut_down);
133}
134
135template <typename I>
136void ManagedLock<I>::acquire_lock(Context *on_acquired) {
137 int r = 0;
138 {
139 Mutex::Locker locker(m_lock);
140 if (is_state_shutdown()) {
141 r = -ESHUTDOWN;
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);
145 return;
146 }
147 }
148
149 if (on_acquired != nullptr) {
150 on_acquired->complete(r);
151 }
152}
153
154template <typename I>
155void ManagedLock<I>::try_acquire_lock(Context *on_acquired) {
156 int r = 0;
157 {
158 Mutex::Locker locker(m_lock);
159 if (is_state_shutdown()) {
160 r = -ESHUTDOWN;
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);
164 return;
165 }
166 }
167
168 if (on_acquired != nullptr) {
169 on_acquired->complete(r);
170 }
171}
172
173template <typename I>
174void ManagedLock<I>::release_lock(Context *on_released) {
175 int r = 0;
176 {
177 Mutex::Locker locker(m_lock);
178 if (is_state_shutdown()) {
179 r = -ESHUTDOWN;
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);
183 return;
184 }
185 }
186
187 if (on_released != nullptr) {
188 on_released->complete(r);
189 }
190}
191
192template <typename I>
193void ManagedLock<I>::reacquire_lock(Context *on_reacquired) {
194 {
195 Mutex::Locker locker(m_lock);
196
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);
212 return;
213 }
214 }
215
216 // ignore request if shutdown or not in a locked-related state
217 if (on_reacquired != nullptr) {
218 on_reacquired->complete(0);
219 }
220}
221
222template <typename I>
223void ManagedLock<I>::get_locker(managed_lock::Locker *locker,
224 Context *on_finish) {
225 ldout(m_cct, 10) << dendl;
226
227 int r;
228 {
229 Mutex::Locker l(m_lock);
230 if (is_state_shutdown()) {
231 r = -ESHUTDOWN;
232 } else {
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);
236 req->send();
237 return;
238 }
239 }
240
241 on_finish->complete(r);
242}
243
244template <typename I>
245void ManagedLock<I>::break_lock(const managed_lock::Locker &locker,
246 bool force_break_lock, Context *on_finish) {
247 ldout(m_cct, 10) << dendl;
248
249 int r;
250 {
251 Mutex::Locker l(m_lock);
252 if (is_state_shutdown()) {
253 r = -ESHUTDOWN;
254 } else if (is_lock_owner(m_lock)) {
255 r = -EBUSY;
256 } else {
257 on_finish = new C_Tracked(m_async_op_tracker, on_finish);
258 auto req = managed_lock::BreakRequest<I>::create(
31f18b77
FG
259 m_ioctx, m_work_queue, m_oid, locker, m_mode == EXCLUSIVE,
260 m_blacklist_on_break_lock, m_blacklist_expire_seconds, force_break_lock,
261 on_finish);
7c673cae
FG
262 req->send();
263 return;
264 }
265 }
266
267 on_finish->complete(r);
268}
269
270template <typename I>
271int ManagedLock<I>::assert_header_locked() {
272 ldout(m_cct, 10) << dendl;
273
274 librados::ObjectReadOperation op;
275 {
276 Mutex::Locker locker(m_lock);
277 rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME,
278 (m_mode == EXCLUSIVE ? LOCK_EXCLUSIVE :
279 LOCK_SHARED),
280 m_cookie,
281 managed_lock::util::get_watcher_lock_tag());
282 }
283
284 int r = m_ioctx.operate(m_oid, &op, nullptr);
285 if (r < 0) {
286 if (r == -EBLACKLISTED) {
287 ldout(m_cct, 5) << "client is not lock owner -- client blacklisted"
288 << dendl;
289 } else if (r == -ENOENT) {
290 ldout(m_cct, 5) << "client is not lock owner -- no lock detected"
291 << dendl;
292 } else if (r == -EBUSY) {
293 ldout(m_cct, 5) << "client is not lock owner -- owned by different client"
294 << dendl;
295 } else {
296 lderr(m_cct) << "failed to verify lock ownership: " << cpp_strerror(r)
297 << dendl;
298 }
299
300 return r;
301 }
302
303 return 0;
304}
305
306template <typename I>
307void ManagedLock<I>::shutdown_handler(int r, Context *on_finish) {
308 on_finish->complete(r);
309}
310
311template <typename I>
312void ManagedLock<I>::pre_acquire_lock_handler(Context *on_finish) {
313 on_finish->complete(0);
314}
315
316template <typename I>
317void ManagedLock<I>::post_acquire_lock_handler(int r, Context *on_finish) {
318 on_finish->complete(r);
319}
320
321template <typename I>
322void ManagedLock<I>::pre_release_lock_handler(bool shutting_down,
323 Context *on_finish) {
324 on_finish->complete(0);
325}
326
327template <typename I>
328void ManagedLock<I>::post_release_lock_handler(bool shutting_down, int r,
329 Context *on_finish) {
330 on_finish->complete(r);
331}
332
31f18b77
FG
333template <typename I>
334void ManagedLock<I>::post_reacquire_lock_handler(int r, Context *on_finish) {
335 on_finish->complete(r);
336}
337
7c673cae
FG
338template <typename I>
339bool ManagedLock<I>::is_transition_state() const {
340 switch (m_state) {
341 case STATE_ACQUIRING:
342 case STATE_WAITING_FOR_REGISTER:
343 case STATE_REACQUIRING:
344 case STATE_RELEASING:
345 case STATE_PRE_SHUTTING_DOWN:
346 case STATE_SHUTTING_DOWN:
347 case STATE_INITIALIZING:
348 case STATE_WAITING_FOR_LOCK:
349 case STATE_POST_ACQUIRING:
350 case STATE_PRE_RELEASING:
351 return true;
352 case STATE_UNLOCKED:
353 case STATE_LOCKED:
354 case STATE_SHUTDOWN:
355 case STATE_UNINITIALIZED:
356 break;
357 }
358 return false;
359}
360
361template <typename I>
362void ManagedLock<I>::append_context(Action action, Context *ctx) {
363 assert(m_lock.is_locked());
364
365 for (auto &action_ctxs : m_actions_contexts) {
366 if (action == action_ctxs.first) {
367 if (ctx != nullptr) {
368 action_ctxs.second.push_back(ctx);
369 }
370 return;
371 }
372 }
373
374 Contexts contexts;
375 if (ctx != nullptr) {
376 contexts.push_back(ctx);
377 }
378 m_actions_contexts.push_back({action, std::move(contexts)});
379}
380
381template <typename I>
382void ManagedLock<I>::execute_action(Action action, Context *ctx) {
383 assert(m_lock.is_locked());
384
385 append_context(action, ctx);
386 if (!is_transition_state()) {
387 execute_next_action();
388 }
389}
390
391template <typename I>
392void ManagedLock<I>::execute_next_action() {
393 assert(m_lock.is_locked());
394 assert(!m_actions_contexts.empty());
395 switch (get_active_action()) {
396 case ACTION_ACQUIRE_LOCK:
397 case ACTION_TRY_LOCK:
398 send_acquire_lock();
399 break;
400 case ACTION_REACQUIRE_LOCK:
401 send_reacquire_lock();
402 break;
403 case ACTION_RELEASE_LOCK:
404 send_release_lock();
405 break;
406 case ACTION_SHUT_DOWN:
407 send_shutdown();
408 break;
409 default:
410 assert(false);
411 break;
412 }
413}
414
415template <typename I>
416typename ManagedLock<I>::Action ManagedLock<I>::get_active_action() const {
417 assert(m_lock.is_locked());
418 assert(!m_actions_contexts.empty());
419 return m_actions_contexts.front().first;
420}
421
422template <typename I>
423void ManagedLock<I>::complete_active_action(State next_state, int r) {
424 assert(m_lock.is_locked());
425 assert(!m_actions_contexts.empty());
426
427 ActionContexts action_contexts(std::move(m_actions_contexts.front()));
428 m_actions_contexts.pop_front();
429 m_state = next_state;
430
431 m_lock.Unlock();
432 for (auto ctx : action_contexts.second) {
433 ctx->complete(r);
434 }
435 m_lock.Lock();
436
437 if (!is_transition_state() && !m_actions_contexts.empty()) {
438 execute_next_action();
439 }
440}
441
442template <typename I>
443bool ManagedLock<I>::is_state_shutdown() const {
444 assert(m_lock.is_locked());
445
446 return ((m_state == STATE_SHUTDOWN) ||
447 (!m_actions_contexts.empty() &&
448 m_actions_contexts.back().first == ACTION_SHUT_DOWN));
449}
450
451template <typename I>
452void ManagedLock<I>::send_acquire_lock() {
453 assert(m_lock.is_locked());
454 if (m_state == STATE_LOCKED) {
455 complete_active_action(STATE_LOCKED, 0);
456 return;
457 }
458
459 ldout(m_cct, 10) << dendl;
460 m_state = STATE_ACQUIRING;
461
462 uint64_t watch_handle = m_watcher->get_watch_handle();
463 if (watch_handle == 0) {
464 lderr(m_cct) << "watcher not registered - delaying request" << dendl;
465 m_state = STATE_WAITING_FOR_REGISTER;
466 return;
467 }
468 m_cookie = encode_lock_cookie(watch_handle);
469
470 m_work_queue->queue(new FunctionContext([this](int r) {
471 pre_acquire_lock_handler(create_context_callback<
472 ManagedLock<I>, &ManagedLock<I>::handle_pre_acquire_lock>(this));
473 }));
474}
475
476template <typename I>
477void ManagedLock<I>::handle_pre_acquire_lock(int r) {
478 ldout(m_cct, 10) << ": r=" << r << dendl;
479
480 if (r < 0) {
481 handle_acquire_lock(r);
482 return;
483 }
484
485 using managed_lock::AcquireRequest;
486 AcquireRequest<I>* req = AcquireRequest<I>::create(
487 m_ioctx, m_watcher, m_work_queue, m_oid, m_cookie, m_mode == EXCLUSIVE,
488 m_blacklist_on_break_lock, m_blacklist_expire_seconds,
489 create_context_callback<
490 ManagedLock<I>, &ManagedLock<I>::handle_acquire_lock>(this));
491 m_work_queue->queue(new C_SendLockRequest<AcquireRequest<I>>(req), 0);
492}
493
494template <typename I>
495void ManagedLock<I>::handle_acquire_lock(int r) {
496 ldout(m_cct, 10) << ": r=" << r << dendl;
497
498 if (r == -EBUSY || r == -EAGAIN) {
499 ldout(m_cct, 5) << ": unable to acquire exclusive lock" << dendl;
500 } else if (r < 0) {
501 lderr(m_cct) << ": failed to acquire exclusive lock:" << cpp_strerror(r)
502 << dendl;
503 } else {
504 ldout(m_cct, 5) << ": successfully acquired exclusive lock" << dendl;
505 }
506
507 m_post_next_state = (r < 0 ? STATE_UNLOCKED : STATE_LOCKED);
508
509 m_work_queue->queue(new FunctionContext([this, r](int ret) {
510 post_acquire_lock_handler(r, create_context_callback<
511 ManagedLock<I>, &ManagedLock<I>::handle_post_acquire_lock>(this));
512 }));
513}
514
515template <typename I>
516void ManagedLock<I>::handle_post_acquire_lock(int r) {
517 ldout(m_cct, 10) << ": r=" << r << dendl;
518
519 Mutex::Locker locker(m_lock);
520
521 if (r < 0 && m_post_next_state == STATE_LOCKED) {
522 // release_lock without calling pre and post handlers
523 revert_to_unlock_state(r);
524 } else if (r != -ECANCELED) {
525 // fail the lock request
526 complete_active_action(m_post_next_state, r);
527 }
528}
529
530template <typename I>
531void ManagedLock<I>::revert_to_unlock_state(int r) {
532 ldout(m_cct, 10) << ": r=" << r << dendl;
533
534 using managed_lock::ReleaseRequest;
535 ReleaseRequest<I>* req = ReleaseRequest<I>::create(m_ioctx, m_watcher,
536 m_work_queue, m_oid, m_cookie,
537 new FunctionContext([this, r](int ret) {
538 Mutex::Locker locker(m_lock);
539 assert(ret == 0);
540 complete_active_action(STATE_UNLOCKED, r);
541 }));
542 m_work_queue->queue(new C_SendLockRequest<ReleaseRequest<I>>(req));
543}
544
545template <typename I>
546void ManagedLock<I>::send_reacquire_lock() {
547 assert(m_lock.is_locked());
548
549 if (m_state != STATE_LOCKED) {
550 complete_active_action(m_state, 0);
551 return;
552 }
553
554 uint64_t watch_handle = m_watcher->get_watch_handle();
555 if (watch_handle == 0) {
556 // watch (re)failed while recovering
557 lderr(m_cct) << ": aborting reacquire due to invalid watch handle"
558 << dendl;
559 complete_active_action(STATE_LOCKED, 0);
560 return;
561 }
562
563 m_new_cookie = encode_lock_cookie(watch_handle);
564 if (m_cookie == m_new_cookie) {
565 ldout(m_cct, 10) << ": skipping reacquire since cookie still valid"
566 << dendl;
567 complete_active_action(STATE_LOCKED, 0);
568 return;
569 }
570
571 ldout(m_cct, 10) << dendl;
572 m_state = STATE_REACQUIRING;
573
31f18b77
FG
574 auto ctx = create_context_callback<
575 ManagedLock, &ManagedLock<I>::handle_reacquire_lock>(this);
576 ctx = new FunctionContext([this, ctx](int r) {
577 post_reacquire_lock_handler(r, ctx);
578 });
579
7c673cae
FG
580 using managed_lock::ReacquireRequest;
581 ReacquireRequest<I>* req = ReacquireRequest<I>::create(m_ioctx, m_oid,
31f18b77 582 m_cookie, m_new_cookie, m_mode == EXCLUSIVE, ctx);
7c673cae
FG
583 m_work_queue->queue(new C_SendLockRequest<ReacquireRequest<I>>(req));
584}
585
586template <typename I>
587void ManagedLock<I>::handle_reacquire_lock(int r) {
588 ldout(m_cct, 10) << ": r=" << r << dendl;
589
590 Mutex::Locker locker(m_lock);
591 assert(m_state == STATE_REACQUIRING);
592
593 if (r < 0) {
594 if (r == -EOPNOTSUPP) {
595 ldout(m_cct, 10) << ": updating lock is not supported" << dendl;
596 } else {
597 lderr(m_cct) << ": failed to update lock cookie: " << cpp_strerror(r)
598 << dendl;
599 }
600
601 if (!is_state_shutdown()) {
602 // queue a release and re-acquire of the lock since cookie cannot
603 // be updated on older OSDs
604 execute_action(ACTION_RELEASE_LOCK, nullptr);
605
606 assert(!m_actions_contexts.empty());
607 ActionContexts &action_contexts(m_actions_contexts.front());
608
609 // reacquire completes when the request lock completes
610 Contexts contexts;
611 std::swap(contexts, action_contexts.second);
612 if (contexts.empty()) {
613 execute_action(ACTION_ACQUIRE_LOCK, nullptr);
614 } else {
615 for (auto ctx : contexts) {
616 ctx = new FunctionContext([ctx, r](int acquire_ret_val) {
617 if (acquire_ret_val >= 0) {
618 acquire_ret_val = r;
619 }
620 ctx->complete(acquire_ret_val);
621 });
622 execute_action(ACTION_ACQUIRE_LOCK, ctx);
623 }
624 }
625 }
626 } else {
627 m_cookie = m_new_cookie;
628 }
629
630 complete_active_action(STATE_LOCKED, r);
631}
632
633template <typename I>
634void ManagedLock<I>::send_release_lock() {
635 assert(m_lock.is_locked());
636 if (m_state == STATE_UNLOCKED) {
637 complete_active_action(STATE_UNLOCKED, 0);
638 return;
639 }
640
641 ldout(m_cct, 10) << dendl;
642 m_state = STATE_PRE_RELEASING;
643
644 m_work_queue->queue(new FunctionContext([this](int r) {
645 pre_release_lock_handler(false, create_context_callback<
646 ManagedLock<I>, &ManagedLock<I>::handle_pre_release_lock>(this));
647 }));
648}
649
650template <typename I>
651void ManagedLock<I>::handle_pre_release_lock(int r) {
652 ldout(m_cct, 10) << ": r=" << r << dendl;
653
654 {
655 Mutex::Locker locker(m_lock);
656 assert(m_state == STATE_PRE_RELEASING);
657 m_state = STATE_RELEASING;
658 }
659
660 if (r < 0) {
661 handle_release_lock(r);
662 return;
663 }
664
665 using managed_lock::ReleaseRequest;
666 ReleaseRequest<I>* req = ReleaseRequest<I>::create(m_ioctx, m_watcher,
667 m_work_queue, m_oid, m_cookie,
668 create_context_callback<
669 ManagedLock<I>, &ManagedLock<I>::handle_release_lock>(this));
670 m_work_queue->queue(new C_SendLockRequest<ReleaseRequest<I>>(req), 0);
671}
672
673template <typename I>
674void ManagedLock<I>::handle_release_lock(int r) {
675 ldout(m_cct, 10) << ": r=" << r << dendl;
676
677 Mutex::Locker locker(m_lock);
678 assert(m_state == STATE_RELEASING);
679
680 if (r >= 0) {
681 m_cookie = "";
682 }
683
684 m_post_next_state = r < 0 ? STATE_LOCKED : STATE_UNLOCKED;
685
686 m_work_queue->queue(new FunctionContext([this, r](int ret) {
687 post_release_lock_handler(false, r, create_context_callback<
688 ManagedLock<I>, &ManagedLock<I>::handle_post_release_lock>(this));
689 }));
690}
691
692template <typename I>
693void ManagedLock<I>::handle_post_release_lock(int r) {
694 ldout(m_cct, 10) << ": r=" << r << dendl;
695
696 Mutex::Locker locker(m_lock);
697 complete_active_action(m_post_next_state, r);
698}
699
700template <typename I>
701void ManagedLock<I>::send_shutdown() {
702 ldout(m_cct, 10) << dendl;
703 assert(m_lock.is_locked());
704 if (m_state == STATE_UNLOCKED) {
705 m_state = STATE_SHUTTING_DOWN;
706 m_work_queue->queue(new FunctionContext([this](int r) {
707 shutdown_handler(r, create_context_callback<
708 ManagedLock<I>, &ManagedLock<I>::handle_shutdown>(this));
709 }));
710 return;
711 }
712
713 assert(m_state == STATE_LOCKED);
714 m_state = STATE_PRE_SHUTTING_DOWN;
715
716 m_lock.Unlock();
717 m_work_queue->queue(new C_ShutDownRelease(this), 0);
718 m_lock.Lock();
719}
720
721template <typename I>
722void ManagedLock<I>::handle_shutdown(int r) {
723 ldout(m_cct, 10) << ": r=" << r << dendl;
724
725 wait_for_tracked_ops(r);
726}
727
728template <typename I>
729void ManagedLock<I>::send_shutdown_release() {
730 ldout(m_cct, 10) << dendl;
731
732 Mutex::Locker locker(m_lock);
733
734 m_work_queue->queue(new FunctionContext([this](int r) {
735 pre_release_lock_handler(true, create_context_callback<
736 ManagedLock<I>, &ManagedLock<I>::handle_shutdown_pre_release>(this));
737 }));
738}
739
740template <typename I>
741void ManagedLock<I>::handle_shutdown_pre_release(int r) {
742 ldout(m_cct, 10) << ": r=" << r << dendl;
743
744 std::string cookie;
745 {
746 Mutex::Locker locker(m_lock);
747 cookie = m_cookie;
748
749 assert(m_state == STATE_PRE_SHUTTING_DOWN);
750 m_state = STATE_SHUTTING_DOWN;
751 }
752
753 using managed_lock::ReleaseRequest;
754 ReleaseRequest<I>* req = ReleaseRequest<I>::create(m_ioctx, m_watcher,
755 m_work_queue, m_oid, cookie,
756 new FunctionContext([this](int r) {
757 post_release_lock_handler(true, r, create_context_callback<
758 ManagedLock<I>, &ManagedLock<I>::handle_shutdown_post_release>(this));
759 }));
760 req->send();
761
762}
763
764template <typename I>
765void ManagedLock<I>::handle_shutdown_post_release(int r) {
766 ldout(m_cct, 10) << ": r=" << r << dendl;
767
768 wait_for_tracked_ops(r);
769}
770
771template <typename I>
772void ManagedLock<I>::wait_for_tracked_ops(int r) {
773 ldout(m_cct, 10) << ": r=" << r << dendl;
774
775 Context *ctx = new FunctionContext([this, r](int ret) {
776 complete_shutdown(r);
777 });
778
779 m_async_op_tracker.wait_for_ops(ctx);
780}
781
782template <typename I>
783void ManagedLock<I>::complete_shutdown(int r) {
784 ldout(m_cct, 10) << ": r=" << r << dendl;
785
786 if (r < 0) {
787 lderr(m_cct) << "failed to shut down lock: " << cpp_strerror(r)
788 << dendl;
789 }
790
791 ActionContexts action_contexts;
792 {
793 Mutex::Locker locker(m_lock);
794 assert(m_lock.is_locked());
795 assert(m_actions_contexts.size() == 1);
796
797 action_contexts = std::move(m_actions_contexts.front());
798 m_actions_contexts.pop_front();
799 m_state = STATE_SHUTDOWN;
800 }
801
802 // expect to be destroyed after firing callback
803 for (auto ctx : action_contexts.second) {
804 ctx->complete(r);
805 }
806}
807
808} // namespace librbd
809
810template class librbd::ManagedLock<librbd::ImageCtx>;