Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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_mode == EXCLUSIVE,
260         m_blacklist_on_break_lock, m_blacklist_expire_seconds, force_break_lock,
261         on_finish);
262       req->send();
263       return;
264     }
265   }
266
267   on_finish->complete(r);
268 }
269
270 template <typename I>
271 int 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
306 template <typename I>
307 void ManagedLock<I>::shutdown_handler(int r, Context *on_finish) {
308   on_finish->complete(r);
309 }
310
311 template <typename I>
312 void ManagedLock<I>::pre_acquire_lock_handler(Context *on_finish) {
313   on_finish->complete(0);
314 }
315
316 template <typename I>
317 void  ManagedLock<I>::post_acquire_lock_handler(int r, Context *on_finish) {
318   on_finish->complete(r);
319 }
320
321 template <typename I>
322 void  ManagedLock<I>::pre_release_lock_handler(bool shutting_down,
323                                                Context *on_finish) {
324   on_finish->complete(0);
325 }
326
327 template <typename I>
328 void  ManagedLock<I>::post_release_lock_handler(bool shutting_down, int r,
329                                                 Context *on_finish) {
330   on_finish->complete(r);
331 }
332
333 template <typename I>
334 void ManagedLock<I>::post_reacquire_lock_handler(int r, Context *on_finish) {
335   on_finish->complete(r);
336 }
337
338 template <typename I>
339 bool 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
361 template <typename I>
362 void 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
381 template <typename I>
382 void 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
391 template <typename I>
392 void 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
415 template <typename I>
416 typename 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
422 template <typename I>
423 void 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
442 template <typename I>
443 bool 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
451 template <typename I>
452 void 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
476 template <typename I>
477 void 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
494 template <typename I>
495 void 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
515 template <typename I>
516 void 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
530 template <typename I>
531 void 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
545 template <typename I>
546 void 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
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
580   using managed_lock::ReacquireRequest;
581   ReacquireRequest<I>* req = ReacquireRequest<I>::create(m_ioctx, m_oid,
582       m_cookie, m_new_cookie, m_mode == EXCLUSIVE, ctx);
583   m_work_queue->queue(new C_SendLockRequest<ReacquireRequest<I>>(req));
584 }
585
586 template <typename I>
587 void 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
633 template <typename I>
634 void 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
650 template <typename I>
651 void 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
673 template <typename I>
674 void 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
692 template <typename I>
693 void 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
700 template <typename I>
701 void 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
721 template <typename I>
722 void ManagedLock<I>::handle_shutdown(int r) {
723   ldout(m_cct, 10) << ": r=" << r << dendl;
724
725   wait_for_tracked_ops(r);
726 }
727
728 template <typename I>
729 void 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
740 template <typename I>
741 void 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
764 template <typename I>
765 void 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
771 template <typename I>
772 void 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
782 template <typename I>
783 void 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
810 template class librbd::ManagedLock<librbd::ImageCtx>;