]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/ManagedLock.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / librbd / ManagedLock.cc
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
25 namespace librbd {
26
27 using std::string;
28 using namespace managed_lock;
29
30 namespace {
31
32 template <typename R>
33 struct 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
42 struct 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
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;
63
64 template <typename I>
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),
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
80 template <typename I>
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
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
95 template <typename I>
96 bool ManagedLock<I>::is_lock_owner() const {
97 Mutex::Locker locker(m_lock);
98
99 return is_lock_owner(m_lock);
100 }
101
102 template <typename I>
103 bool 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
126 template <typename I>
127 void 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
135 template <typename I>
136 void 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
154 template <typename I>
155 void 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
173 template <typename I>
174 void 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
192 template <typename I>
193 void 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
222 template <typename I>
223 void 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
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;
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(
259 m_ioctx, m_work_queue, m_oid, locker, m_blacklist_on_break_lock,
260 m_blacklist_expire_seconds, force_break_lock, on_finish);
261 req->send();
262 return;
263 }
264 }
265
266 on_finish->complete(r);
267 }
268
269 template <typename I>
270 int ManagedLock<I>::assert_header_locked() {
271 ldout(m_cct, 10) << dendl;
272
273 librados::ObjectReadOperation op;
274 {
275 Mutex::Locker locker(m_lock);
276 rados::cls::lock::assert_locked(&op, RBD_LOCK_NAME,
277 (m_mode == EXCLUSIVE ? LOCK_EXCLUSIVE :
278 LOCK_SHARED),
279 m_cookie,
280 managed_lock::util::get_watcher_lock_tag());
281 }
282
283 int r = m_ioctx.operate(m_oid, &op, nullptr);
284 if (r < 0) {
285 if (r == -EBLACKLISTED) {
286 ldout(m_cct, 5) << "client is not lock owner -- client blacklisted"
287 << dendl;
288 } else if (r == -ENOENT) {
289 ldout(m_cct, 5) << "client is not lock owner -- no lock detected"
290 << dendl;
291 } else if (r == -EBUSY) {
292 ldout(m_cct, 5) << "client is not lock owner -- owned by different client"
293 << dendl;
294 } else {
295 lderr(m_cct) << "failed to verify lock ownership: " << cpp_strerror(r)
296 << dendl;
297 }
298
299 return r;
300 }
301
302 return 0;
303 }
304
305 template <typename I>
306 void ManagedLock<I>::shutdown_handler(int r, Context *on_finish) {
307 on_finish->complete(r);
308 }
309
310 template <typename I>
311 void ManagedLock<I>::pre_acquire_lock_handler(Context *on_finish) {
312 on_finish->complete(0);
313 }
314
315 template <typename I>
316 void ManagedLock<I>::post_acquire_lock_handler(int r, Context *on_finish) {
317 on_finish->complete(r);
318 }
319
320 template <typename I>
321 void ManagedLock<I>::pre_release_lock_handler(bool shutting_down,
322 Context *on_finish) {
323 on_finish->complete(0);
324 }
325
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);
330 }
331
332 template <typename I>
333 bool ManagedLock<I>::is_transition_state() const {
334 switch (m_state) {
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:
345 return true;
346 case STATE_UNLOCKED:
347 case STATE_LOCKED:
348 case STATE_SHUTDOWN:
349 case STATE_UNINITIALIZED:
350 break;
351 }
352 return false;
353 }
354
355 template <typename I>
356 void ManagedLock<I>::append_context(Action action, Context *ctx) {
357 assert(m_lock.is_locked());
358
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);
363 }
364 return;
365 }
366 }
367
368 Contexts contexts;
369 if (ctx != nullptr) {
370 contexts.push_back(ctx);
371 }
372 m_actions_contexts.push_back({action, std::move(contexts)});
373 }
374
375 template <typename I>
376 void ManagedLock<I>::execute_action(Action action, Context *ctx) {
377 assert(m_lock.is_locked());
378
379 append_context(action, ctx);
380 if (!is_transition_state()) {
381 execute_next_action();
382 }
383 }
384
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:
392 send_acquire_lock();
393 break;
394 case ACTION_REACQUIRE_LOCK:
395 send_reacquire_lock();
396 break;
397 case ACTION_RELEASE_LOCK:
398 send_release_lock();
399 break;
400 case ACTION_SHUT_DOWN:
401 send_shutdown();
402 break;
403 default:
404 assert(false);
405 break;
406 }
407 }
408
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;
414 }
415
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());
420
421 ActionContexts action_contexts(std::move(m_actions_contexts.front()));
422 m_actions_contexts.pop_front();
423 m_state = next_state;
424
425 m_lock.Unlock();
426 for (auto ctx : action_contexts.second) {
427 ctx->complete(r);
428 }
429 m_lock.Lock();
430
431 if (!is_transition_state() && !m_actions_contexts.empty()) {
432 execute_next_action();
433 }
434 }
435
436 template <typename I>
437 bool ManagedLock<I>::is_state_shutdown() const {
438 assert(m_lock.is_locked());
439
440 return ((m_state == STATE_SHUTDOWN) ||
441 (!m_actions_contexts.empty() &&
442 m_actions_contexts.back().first == ACTION_SHUT_DOWN));
443 }
444
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);
450 return;
451 }
452
453 ldout(m_cct, 10) << dendl;
454 m_state = STATE_ACQUIRING;
455
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;
460 return;
461 }
462 m_cookie = encode_lock_cookie(watch_handle);
463
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));
467 }));
468 }
469
470 template <typename I>
471 void ManagedLock<I>::handle_pre_acquire_lock(int r) {
472 ldout(m_cct, 10) << ": r=" << r << dendl;
473
474 if (r < 0) {
475 handle_acquire_lock(r);
476 return;
477 }
478
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);
486 }
487
488 template <typename I>
489 void ManagedLock<I>::handle_acquire_lock(int r) {
490 ldout(m_cct, 10) << ": r=" << r << dendl;
491
492 if (r == -EBUSY || r == -EAGAIN) {
493 ldout(m_cct, 5) << ": unable to acquire exclusive lock" << dendl;
494 } else if (r < 0) {
495 lderr(m_cct) << ": failed to acquire exclusive lock:" << cpp_strerror(r)
496 << dendl;
497 } else {
498 ldout(m_cct, 5) << ": successfully acquired exclusive lock" << dendl;
499 }
500
501 m_post_next_state = (r < 0 ? STATE_UNLOCKED : STATE_LOCKED);
502
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));
506 }));
507 }
508
509 template <typename I>
510 void ManagedLock<I>::handle_post_acquire_lock(int r) {
511 ldout(m_cct, 10) << ": r=" << r << dendl;
512
513 Mutex::Locker locker(m_lock);
514
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);
521 }
522 }
523
524 template <typename I>
525 void ManagedLock<I>::revert_to_unlock_state(int r) {
526 ldout(m_cct, 10) << ": r=" << r << dendl;
527
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);
533 assert(ret == 0);
534 complete_active_action(STATE_UNLOCKED, r);
535 }));
536 m_work_queue->queue(new C_SendLockRequest<ReleaseRequest<I>>(req));
537 }
538
539 template <typename I>
540 void ManagedLock<I>::send_reacquire_lock() {
541 assert(m_lock.is_locked());
542
543 if (m_state != STATE_LOCKED) {
544 complete_active_action(m_state, 0);
545 return;
546 }
547
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"
552 << dendl;
553 complete_active_action(STATE_LOCKED, 0);
554 return;
555 }
556
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"
560 << dendl;
561 complete_active_action(STATE_LOCKED, 0);
562 return;
563 }
564
565 ldout(m_cct, 10) << dendl;
566 m_state = STATE_REACQUIRING;
567
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));
574 }
575
576 template <typename I>
577 void ManagedLock<I>::handle_reacquire_lock(int r) {
578 ldout(m_cct, 10) << ": r=" << r << dendl;
579
580 Mutex::Locker locker(m_lock);
581 assert(m_state == STATE_REACQUIRING);
582
583 if (r < 0) {
584 if (r == -EOPNOTSUPP) {
585 ldout(m_cct, 10) << ": updating lock is not supported" << dendl;
586 } else {
587 lderr(m_cct) << ": failed to update lock cookie: " << cpp_strerror(r)
588 << dendl;
589 }
590
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);
595
596 assert(!m_actions_contexts.empty());
597 ActionContexts &action_contexts(m_actions_contexts.front());
598
599 // reacquire completes when the request lock completes
600 Contexts contexts;
601 std::swap(contexts, action_contexts.second);
602 if (contexts.empty()) {
603 execute_action(ACTION_ACQUIRE_LOCK, nullptr);
604 } else {
605 for (auto ctx : contexts) {
606 ctx = new FunctionContext([ctx, r](int acquire_ret_val) {
607 if (acquire_ret_val >= 0) {
608 acquire_ret_val = r;
609 }
610 ctx->complete(acquire_ret_val);
611 });
612 execute_action(ACTION_ACQUIRE_LOCK, ctx);
613 }
614 }
615 }
616 } else {
617 m_cookie = m_new_cookie;
618 }
619
620 complete_active_action(STATE_LOCKED, r);
621 }
622
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);
628 return;
629 }
630
631 ldout(m_cct, 10) << dendl;
632 m_state = STATE_PRE_RELEASING;
633
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));
637 }));
638 }
639
640 template <typename I>
641 void ManagedLock<I>::handle_pre_release_lock(int r) {
642 ldout(m_cct, 10) << ": r=" << r << dendl;
643
644 {
645 Mutex::Locker locker(m_lock);
646 assert(m_state == STATE_PRE_RELEASING);
647 m_state = STATE_RELEASING;
648 }
649
650 if (r < 0) {
651 handle_release_lock(r);
652 return;
653 }
654
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);
661 }
662
663 template <typename I>
664 void ManagedLock<I>::handle_release_lock(int r) {
665 ldout(m_cct, 10) << ": r=" << r << dendl;
666
667 Mutex::Locker locker(m_lock);
668 assert(m_state == STATE_RELEASING);
669
670 if (r >= 0) {
671 m_cookie = "";
672 }
673
674 m_post_next_state = r < 0 ? STATE_LOCKED : STATE_UNLOCKED;
675
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));
679 }));
680 }
681
682 template <typename I>
683 void ManagedLock<I>::handle_post_release_lock(int r) {
684 ldout(m_cct, 10) << ": r=" << r << dendl;
685
686 Mutex::Locker locker(m_lock);
687 complete_active_action(m_post_next_state, r);
688 }
689
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));
699 }));
700 return;
701 }
702
703 assert(m_state == STATE_LOCKED);
704 m_state = STATE_PRE_SHUTTING_DOWN;
705
706 m_lock.Unlock();
707 m_work_queue->queue(new C_ShutDownRelease(this), 0);
708 m_lock.Lock();
709 }
710
711 template <typename I>
712 void ManagedLock<I>::handle_shutdown(int r) {
713 ldout(m_cct, 10) << ": r=" << r << dendl;
714
715 wait_for_tracked_ops(r);
716 }
717
718 template <typename I>
719 void ManagedLock<I>::send_shutdown_release() {
720 ldout(m_cct, 10) << dendl;
721
722 Mutex::Locker locker(m_lock);
723
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));
727 }));
728 }
729
730 template <typename I>
731 void ManagedLock<I>::handle_shutdown_pre_release(int r) {
732 ldout(m_cct, 10) << ": r=" << r << dendl;
733
734 std::string cookie;
735 {
736 Mutex::Locker locker(m_lock);
737 cookie = m_cookie;
738
739 assert(m_state == STATE_PRE_SHUTTING_DOWN);
740 m_state = STATE_SHUTTING_DOWN;
741 }
742
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));
749 }));
750 req->send();
751
752 }
753
754 template <typename I>
755 void ManagedLock<I>::handle_shutdown_post_release(int r) {
756 ldout(m_cct, 10) << ": r=" << r << dendl;
757
758 wait_for_tracked_ops(r);
759 }
760
761 template <typename I>
762 void ManagedLock<I>::wait_for_tracked_ops(int r) {
763 ldout(m_cct, 10) << ": r=" << r << dendl;
764
765 Context *ctx = new FunctionContext([this, r](int ret) {
766 complete_shutdown(r);
767 });
768
769 m_async_op_tracker.wait_for_ops(ctx);
770 }
771
772 template <typename I>
773 void ManagedLock<I>::complete_shutdown(int r) {
774 ldout(m_cct, 10) << ": r=" << r << dendl;
775
776 if (r < 0) {
777 lderr(m_cct) << "failed to shut down lock: " << cpp_strerror(r)
778 << dendl;
779 }
780
781 ActionContexts action_contexts;
782 {
783 Mutex::Locker locker(m_lock);
784 assert(m_lock.is_locked());
785 assert(m_actions_contexts.size() == 1);
786
787 action_contexts = std::move(m_actions_contexts.front());
788 m_actions_contexts.pop_front();
789 m_state = STATE_SHUTDOWN;
790 }
791
792 // expect to be destroyed after firing callback
793 for (auto ctx : action_contexts.second) {
794 ctx->complete(r);
795 }
796 }
797
798 } // namespace librbd
799
800 template class librbd::ManagedLock<librbd::ImageCtx>;