Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / ImageState.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/ImageState.h"
5 #include "include/rbd/librbd.hpp"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "common/Cond.h"
9 #include "common/WorkQueue.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/Utils.h"
12 #include "librbd/image/CloseRequest.h"
13 #include "librbd/image/OpenRequest.h"
14 #include "librbd/image/RefreshRequest.h"
15 #include "librbd/image/SetSnapRequest.h"
16
17 #define dout_subsys ceph_subsys_rbd
18 #undef dout_prefix
19 #define dout_prefix *_dout << "librbd::ImageState: " << this << " "
20
21 namespace librbd {
22
23 using util::create_async_context_callback;
24 using util::create_context_callback;
25
26 class ImageUpdateWatchers {
27 public:
28
29   ImageUpdateWatchers(CephContext *cct) : m_cct(cct),
30     m_lock(util::unique_lock_name("librbd::ImageUpdateWatchers::m_lock", this)) {
31   }
32
33   ~ImageUpdateWatchers() {
34     assert(m_watchers.empty());
35     assert(m_in_flight.empty());
36     assert(m_pending_unregister.empty());
37     assert(m_on_shut_down_finish == nullptr);
38
39     destroy_work_queue();
40   }
41
42   void flush(Context *on_finish) {
43     ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << dendl;
44     {
45       Mutex::Locker locker(m_lock);
46       if (!m_in_flight.empty()) {
47         Context *ctx = new FunctionContext(
48           [this, on_finish](int r) {
49             ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__
50                              << ": completing flush" << dendl;
51             on_finish->complete(r);
52           });
53         m_work_queue->queue(ctx, 0);
54         return;
55       }
56     }
57     ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__
58                      << ": completing flush" << dendl;
59     on_finish->complete(0);
60   }
61
62   void shut_down(Context *on_finish) {
63     ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << dendl;
64     {
65       Mutex::Locker locker(m_lock);
66       assert(m_on_shut_down_finish == nullptr);
67       m_watchers.clear();
68       if (!m_in_flight.empty()) {
69         m_on_shut_down_finish = on_finish;
70         return;
71       }
72     }
73     ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__
74                      << ": completing shut down" << dendl;
75     on_finish->complete(0);
76   }
77
78   void register_watcher(UpdateWatchCtx *watcher, uint64_t *handle) {
79     ldout(m_cct, 20) << __func__ << ": watcher=" << watcher << dendl;
80
81     Mutex::Locker locker(m_lock);
82     assert(m_on_shut_down_finish == nullptr);
83
84     create_work_queue();
85
86     *handle = m_next_handle++;
87     m_watchers.insert(std::make_pair(*handle, watcher));
88   }
89
90   void unregister_watcher(uint64_t handle, Context *on_finish) {
91     ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << ": handle="
92                      << handle << dendl;
93     int r = 0;
94     {
95       Mutex::Locker locker(m_lock);
96       auto it = m_watchers.find(handle);
97       if (it == m_watchers.end()) {
98         r = -ENOENT;
99       } else {
100         if (m_in_flight.find(handle) != m_in_flight.end()) {
101           assert(m_pending_unregister.find(handle) == m_pending_unregister.end());
102           m_pending_unregister[handle] = on_finish;
103           on_finish = nullptr;
104         }
105         m_watchers.erase(it);
106       }
107     }
108
109     if (on_finish) {
110       ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__
111                        << ": completing unregister" << dendl;
112       on_finish->complete(r);
113     }
114   }
115
116   void notify() {
117     ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << dendl;
118
119     Mutex::Locker locker(m_lock);
120     for (auto it : m_watchers) {
121       send_notify(it.first, it.second);
122     }
123   }
124
125   void send_notify(uint64_t handle, UpdateWatchCtx *watcher) {
126     assert(m_lock.is_locked());
127
128     ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << ": handle="
129                      << handle << ", watcher=" << watcher << dendl;
130
131     m_in_flight.insert(handle);
132
133     Context *ctx = new FunctionContext(
134       [this, handle, watcher](int r) {
135         handle_notify(handle, watcher);
136       });
137
138     m_work_queue->queue(ctx, 0);
139   }
140
141   void handle_notify(uint64_t handle, UpdateWatchCtx *watcher) {
142
143     ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << ": handle="
144                      << handle << ", watcher=" << watcher << dendl;
145
146     watcher->handle_notify();
147
148     Context *on_unregister_finish = nullptr;
149     Context *on_shut_down_finish = nullptr;
150
151     {
152       Mutex::Locker locker(m_lock);
153
154       auto in_flight_it = m_in_flight.find(handle);
155       assert(in_flight_it != m_in_flight.end());
156       m_in_flight.erase(in_flight_it);
157
158       // If there is no more in flight notifications for this watcher
159       // and it is pending unregister, complete it now.
160       if (m_in_flight.find(handle) == m_in_flight.end()) {
161         auto it = m_pending_unregister.find(handle);
162         if (it != m_pending_unregister.end()) {
163           on_unregister_finish = it->second;
164           m_pending_unregister.erase(it);
165         }
166       }
167
168       if (m_in_flight.empty()) {
169         assert(m_pending_unregister.empty());
170         if (m_on_shut_down_finish != nullptr) {
171           std::swap(m_on_shut_down_finish, on_shut_down_finish);
172         }
173       }
174     }
175
176     if (on_unregister_finish != nullptr) {
177       ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__
178                        << ": completing unregister" << dendl;
179       on_unregister_finish->complete(0);
180     }
181
182     if (on_shut_down_finish != nullptr) {
183       ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__
184                        << ": completing shut down" << dendl;
185       on_shut_down_finish->complete(0);
186     }
187   }
188
189 private:
190   class ThreadPoolSingleton : public ThreadPool {
191   public:
192     explicit ThreadPoolSingleton(CephContext *cct)
193       : ThreadPool(cct, "librbd::ImageUpdateWatchers::thread_pool", "tp_librbd",
194                    1) {
195       start();
196     }
197     ~ThreadPoolSingleton() override {
198       stop();
199     }
200   };
201
202   CephContext *m_cct;
203   Mutex m_lock;
204   ContextWQ *m_work_queue = nullptr;
205   std::map<uint64_t, UpdateWatchCtx*> m_watchers;
206   uint64_t m_next_handle = 0;
207   std::multiset<uint64_t> m_in_flight;
208   std::map<uint64_t, Context*> m_pending_unregister;
209   Context *m_on_shut_down_finish = nullptr;
210
211   void create_work_queue() {
212     if (m_work_queue != nullptr) {
213       return;
214     }
215     ThreadPoolSingleton *thread_pool_singleton;
216     m_cct->lookup_or_create_singleton_object<ThreadPoolSingleton>(
217       thread_pool_singleton, "librbd::ImageUpdateWatchers::thread_pool");
218     m_work_queue = new ContextWQ("librbd::ImageUpdateWatchers::op_work_queue",
219                                  m_cct->_conf->get_val<int64_t>("rbd_op_thread_timeout"),
220                                  thread_pool_singleton);
221   }
222
223   void destroy_work_queue() {
224     if (m_work_queue == nullptr) {
225       return;
226     }
227     m_work_queue->drain();
228     delete m_work_queue;
229   }
230 };
231
232 template <typename I>
233 ImageState<I>::ImageState(I *image_ctx)
234   : m_image_ctx(image_ctx), m_state(STATE_UNINITIALIZED),
235     m_lock(util::unique_lock_name("librbd::ImageState::m_lock", this)),
236     m_last_refresh(0), m_refresh_seq(0),
237     m_update_watchers(new ImageUpdateWatchers(image_ctx->cct)),
238     m_skip_open_parent_image(false) {
239 }
240
241 template <typename I>
242 ImageState<I>::~ImageState() {
243   assert(m_state == STATE_UNINITIALIZED || m_state == STATE_CLOSED);
244   delete m_update_watchers;
245 }
246
247 template <typename I>
248 int ImageState<I>::open(bool skip_open_parent) {
249   C_SaferCond ctx;
250   open(skip_open_parent, &ctx);
251
252   int r = ctx.wait();
253   if (r < 0) {
254     delete m_image_ctx;
255   }
256   return r;
257 }
258
259 template <typename I>
260 void ImageState<I>::open(bool skip_open_parent, Context *on_finish) {
261   CephContext *cct = m_image_ctx->cct;
262   ldout(cct, 20) << __func__ << dendl;
263
264   m_lock.Lock();
265   assert(m_state == STATE_UNINITIALIZED);
266   m_skip_open_parent_image = skip_open_parent;
267
268   Action action(ACTION_TYPE_OPEN);
269   action.refresh_seq = m_refresh_seq;
270
271   execute_action_unlock(action, on_finish);
272 }
273
274 template <typename I>
275 int ImageState<I>::close() {
276   C_SaferCond ctx;
277   close(&ctx);
278
279   int r = ctx.wait();
280   delete m_image_ctx;
281   return r;
282 }
283
284 template <typename I>
285 void ImageState<I>::close(Context *on_finish) {
286   CephContext *cct = m_image_ctx->cct;
287   ldout(cct, 20) << __func__ << dendl;
288
289   m_lock.Lock();
290   assert(!is_closed());
291
292   Action action(ACTION_TYPE_CLOSE);
293   action.refresh_seq = m_refresh_seq;
294   execute_action_unlock(action, on_finish);
295 }
296
297 template <typename I>
298 void ImageState<I>::handle_update_notification() {
299   Mutex::Locker locker(m_lock);
300   ++m_refresh_seq;
301
302   CephContext *cct = m_image_ctx->cct;
303   ldout(cct, 20) << __func__ << ": refresh_seq = " << m_refresh_seq << ", "
304                  << "last_refresh = " << m_last_refresh << dendl;
305
306   if (m_state == STATE_OPEN) {
307     m_update_watchers->notify();
308   }
309 }
310
311 template <typename I>
312 bool ImageState<I>::is_refresh_required() const {
313   Mutex::Locker locker(m_lock);
314   return (m_last_refresh != m_refresh_seq || find_pending_refresh() != nullptr);
315 }
316
317 template <typename I>
318 int ImageState<I>::refresh() {
319   C_SaferCond refresh_ctx;
320   refresh(&refresh_ctx);
321   return refresh_ctx.wait();
322 }
323
324 template <typename I>
325 void ImageState<I>::refresh(Context *on_finish) {
326   CephContext *cct = m_image_ctx->cct;
327   ldout(cct, 20) << __func__ << dendl;
328
329   m_lock.Lock();
330   if (is_closed()) {
331     m_lock.Unlock();
332     on_finish->complete(-ESHUTDOWN);
333     return;
334   }
335
336   Action action(ACTION_TYPE_REFRESH);
337   action.refresh_seq = m_refresh_seq;
338   execute_action_unlock(action, on_finish);
339 }
340
341 template <typename I>
342 int ImageState<I>::refresh_if_required() {
343   C_SaferCond ctx;
344   {
345     m_lock.Lock();
346     Action action(ACTION_TYPE_REFRESH);
347     action.refresh_seq = m_refresh_seq;
348
349     auto refresh_action = find_pending_refresh();
350     if (refresh_action != nullptr) {
351       // if a refresh is in-flight, delay until it is finished
352       action = *refresh_action;
353     } else if (m_last_refresh == m_refresh_seq) {
354       m_lock.Unlock();
355       return 0;
356     } else if (is_closed()) {
357       m_lock.Unlock();
358       return -ESHUTDOWN;
359     }
360
361     execute_action_unlock(action, &ctx);
362   }
363
364   return ctx.wait();
365 }
366
367 template <typename I>
368 const typename ImageState<I>::Action *
369 ImageState<I>::find_pending_refresh() const {
370   assert(m_lock.is_locked());
371
372   auto it = std::find_if(m_actions_contexts.rbegin(),
373                          m_actions_contexts.rend(),
374                          [](const ActionContexts& action_contexts) {
375       return (action_contexts.first == ACTION_TYPE_REFRESH);
376     });
377   if (it != m_actions_contexts.rend()) {
378     return &it->first;
379   }
380   return nullptr;
381 }
382
383 template <typename I>
384 void ImageState<I>::snap_set(const cls::rbd::SnapshotNamespace &snap_namespace,
385                              const std::string &snap_name,
386                              Context *on_finish) {
387   CephContext *cct = m_image_ctx->cct;
388   ldout(cct, 20) << __func__ << ": snap_name=" << snap_name << dendl;
389
390   Action action(ACTION_TYPE_SET_SNAP);
391   action.snap_namespace = snap_namespace;
392   action.snap_name = snap_name;
393
394   m_lock.Lock();
395   execute_action_unlock(action, on_finish);
396 }
397
398 template <typename I>
399 void ImageState<I>::prepare_lock(Context *on_ready) {
400   CephContext *cct = m_image_ctx->cct;
401   ldout(cct, 10) << __func__ << dendl;
402
403   m_lock.Lock();
404   if (is_closed()) {
405     m_lock.Unlock();
406     on_ready->complete(-ESHUTDOWN);
407     return;
408   }
409
410   Action action(ACTION_TYPE_LOCK);
411   action.on_ready = on_ready;
412   execute_action_unlock(action, nullptr);
413 }
414
415 template <typename I>
416 void ImageState<I>::handle_prepare_lock_complete() {
417   CephContext *cct = m_image_ctx->cct;
418   ldout(cct, 10) << __func__ << dendl;
419
420   m_lock.Lock();
421   if (m_state != STATE_PREPARING_LOCK) {
422     m_lock.Unlock();
423     return;
424   }
425
426   complete_action_unlock(STATE_OPEN, 0);
427 }
428
429 template <typename I>
430 int ImageState<I>::register_update_watcher(UpdateWatchCtx *watcher,
431                                          uint64_t *handle) {
432   CephContext *cct = m_image_ctx->cct;
433   ldout(cct, 20) << __func__ << dendl;
434
435   m_update_watchers->register_watcher(watcher, handle);
436
437   ldout(cct, 20) << __func__ << ": handle=" << *handle << dendl;
438   return 0;
439 }
440
441 template <typename I>
442 int ImageState<I>::unregister_update_watcher(uint64_t handle) {
443   CephContext *cct = m_image_ctx->cct;
444   ldout(cct, 20) << __func__ << ": handle=" << handle << dendl;
445
446   C_SaferCond ctx;
447   m_update_watchers->unregister_watcher(handle, &ctx);
448   return ctx.wait();
449 }
450
451 template <typename I>
452 void ImageState<I>::flush_update_watchers(Context *on_finish) {
453   CephContext *cct = m_image_ctx->cct;
454   ldout(cct, 20) << __func__ << dendl;
455
456   m_update_watchers->flush(on_finish);
457 }
458
459 template <typename I>
460 void ImageState<I>::shut_down_update_watchers(Context *on_finish) {
461   CephContext *cct = m_image_ctx->cct;
462   ldout(cct, 20) << __func__ << dendl;
463
464   m_update_watchers->shut_down(on_finish);
465 }
466
467 template <typename I>
468 bool ImageState<I>::is_transition_state() const {
469   switch (m_state) {
470   case STATE_UNINITIALIZED:
471   case STATE_OPEN:
472   case STATE_CLOSED:
473     return false;
474   case STATE_OPENING:
475   case STATE_CLOSING:
476   case STATE_REFRESHING:
477   case STATE_SETTING_SNAP:
478   case STATE_PREPARING_LOCK:
479     break;
480   }
481   return true;
482 }
483
484 template <typename I>
485 bool ImageState<I>::is_closed() const {
486   assert(m_lock.is_locked());
487
488   return ((m_state == STATE_CLOSED) ||
489           (!m_actions_contexts.empty() &&
490            m_actions_contexts.back().first.action_type == ACTION_TYPE_CLOSE));
491 }
492
493 template <typename I>
494 void ImageState<I>::append_context(const Action &action, Context *context) {
495   assert(m_lock.is_locked());
496
497   ActionContexts *action_contexts = nullptr;
498   for (auto &action_ctxs : m_actions_contexts) {
499     if (action == action_ctxs.first) {
500       action_contexts = &action_ctxs;
501       break;
502     }
503   }
504
505   if (action_contexts == nullptr) {
506     m_actions_contexts.push_back({action, {}});
507     action_contexts = &m_actions_contexts.back();
508   }
509
510   if (context != nullptr) {
511     action_contexts->second.push_back(context);
512   }
513 }
514
515 template <typename I>
516 void ImageState<I>::execute_next_action_unlock() {
517   assert(m_lock.is_locked());
518   assert(!m_actions_contexts.empty());
519   switch (m_actions_contexts.front().first.action_type) {
520   case ACTION_TYPE_OPEN:
521     send_open_unlock();
522     return;
523   case ACTION_TYPE_CLOSE:
524     send_close_unlock();
525     return;
526   case ACTION_TYPE_REFRESH:
527     send_refresh_unlock();
528     return;
529   case ACTION_TYPE_SET_SNAP:
530     send_set_snap_unlock();
531     return;
532   case ACTION_TYPE_LOCK:
533     send_prepare_lock_unlock();
534     return;
535   }
536   assert(false);
537 }
538
539 template <typename I>
540 void ImageState<I>::execute_action_unlock(const Action &action,
541                                           Context *on_finish) {
542   assert(m_lock.is_locked());
543
544   append_context(action, on_finish);
545   if (!is_transition_state()) {
546     execute_next_action_unlock();
547   } else {
548     m_lock.Unlock();
549   }
550 }
551
552 template <typename I>
553 void ImageState<I>::complete_action_unlock(State next_state, int r) {
554   assert(m_lock.is_locked());
555   assert(!m_actions_contexts.empty());
556
557   ActionContexts action_contexts(std::move(m_actions_contexts.front()));
558   m_actions_contexts.pop_front();
559
560   m_state = next_state;
561   m_lock.Unlock();
562
563   for (auto ctx : action_contexts.second) {
564     ctx->complete(r);
565   }
566
567   if (next_state != STATE_UNINITIALIZED && next_state != STATE_CLOSED) {
568     m_lock.Lock();
569     if (!is_transition_state() && !m_actions_contexts.empty()) {
570       execute_next_action_unlock();
571     } else {
572       m_lock.Unlock();
573     }
574   }
575 }
576
577 template <typename I>
578 void ImageState<I>::send_open_unlock() {
579   assert(m_lock.is_locked());
580   CephContext *cct = m_image_ctx->cct;
581   ldout(cct, 10) << this << " " << __func__ << dendl;
582
583   m_state = STATE_OPENING;
584
585   Context *ctx = create_async_context_callback(
586     *m_image_ctx, create_context_callback<
587       ImageState<I>, &ImageState<I>::handle_open>(this));
588   image::OpenRequest<I> *req = image::OpenRequest<I>::create(
589     m_image_ctx, m_skip_open_parent_image, ctx);
590
591   m_lock.Unlock();
592   req->send();
593 }
594
595 template <typename I>
596 void ImageState<I>::handle_open(int r) {
597   CephContext *cct = m_image_ctx->cct;
598   ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
599
600   if (r < 0 && r != -ENOENT) {
601     lderr(cct) << "failed to open image: " << cpp_strerror(r) << dendl;
602   }
603
604   m_lock.Lock();
605   complete_action_unlock(r < 0 ? STATE_UNINITIALIZED : STATE_OPEN, r);
606 }
607
608 template <typename I>
609 void ImageState<I>::send_close_unlock() {
610   assert(m_lock.is_locked());
611   CephContext *cct = m_image_ctx->cct;
612   ldout(cct, 10) << this << " " << __func__ << dendl;
613
614   m_state = STATE_CLOSING;
615
616   Context *ctx = create_context_callback<
617     ImageState<I>, &ImageState<I>::handle_close>(this);
618   image::CloseRequest<I> *req = image::CloseRequest<I>::create(
619     m_image_ctx, ctx);
620
621   m_lock.Unlock();
622   req->send();
623 }
624
625 template <typename I>
626 void ImageState<I>::handle_close(int r) {
627   CephContext *cct = m_image_ctx->cct;
628   ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
629
630   if (r < 0) {
631     lderr(cct) << "error occurred while closing image: " << cpp_strerror(r)
632                << dendl;
633   }
634
635   m_lock.Lock();
636   complete_action_unlock(STATE_CLOSED, r);
637 }
638
639 template <typename I>
640 void ImageState<I>::send_refresh_unlock() {
641   assert(m_lock.is_locked());
642   CephContext *cct = m_image_ctx->cct;
643   ldout(cct, 10) << this << " " << __func__ << dendl;
644
645   m_state = STATE_REFRESHING;
646   assert(!m_actions_contexts.empty());
647   auto &action_context = m_actions_contexts.front().first;
648   assert(action_context.action_type == ACTION_TYPE_REFRESH);
649
650   Context *ctx = create_async_context_callback(
651     *m_image_ctx, create_context_callback<
652       ImageState<I>, &ImageState<I>::handle_refresh>(this));
653   image::RefreshRequest<I> *req = image::RefreshRequest<I>::create(
654     *m_image_ctx, false, false, ctx);
655
656   m_lock.Unlock();
657   req->send();
658 }
659
660 template <typename I>
661 void ImageState<I>::handle_refresh(int r) {
662   CephContext *cct = m_image_ctx->cct;
663   ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl;
664
665   m_lock.Lock();
666   assert(!m_actions_contexts.empty());
667
668   ActionContexts &action_contexts(m_actions_contexts.front());
669   assert(action_contexts.first.action_type == ACTION_TYPE_REFRESH);
670   assert(m_last_refresh <= action_contexts.first.refresh_seq);
671
672   if (r == -ERESTART) {
673     ldout(cct, 5) << "incomplete refresh: not updating sequence" << dendl;
674     r = 0;
675   } else {
676     m_last_refresh = action_contexts.first.refresh_seq;
677   }
678
679   complete_action_unlock(STATE_OPEN, r);
680 }
681
682 template <typename I>
683 void ImageState<I>::send_set_snap_unlock() {
684   assert(m_lock.is_locked());
685
686   m_state = STATE_SETTING_SNAP;
687
688   assert(!m_actions_contexts.empty());
689   ActionContexts &action_contexts(m_actions_contexts.front());
690   assert(action_contexts.first.action_type == ACTION_TYPE_SET_SNAP);
691
692   CephContext *cct = m_image_ctx->cct;
693   ldout(cct, 10) << this << " " << __func__ << ": "
694                  << "snap_name=" << action_contexts.first.snap_name << dendl;
695
696   Context *ctx = create_async_context_callback(
697     *m_image_ctx, create_context_callback<
698       ImageState<I>, &ImageState<I>::handle_set_snap>(this));
699   image::SetSnapRequest<I> *req = image::SetSnapRequest<I>::create(
700     *m_image_ctx, action_contexts.first.snap_namespace, action_contexts.first.snap_name, ctx);
701
702   m_lock.Unlock();
703   req->send();
704 }
705
706 template <typename I>
707 void ImageState<I>::handle_set_snap(int r) {
708   CephContext *cct = m_image_ctx->cct;
709   ldout(cct, 10) << this << " " << __func__ << " r=" << r << dendl;
710
711   if (r < 0 && r != -ENOENT) {
712     lderr(cct) << "failed to set snapshot: " << cpp_strerror(r) << dendl;
713   }
714
715   m_lock.Lock();
716   complete_action_unlock(STATE_OPEN, r);
717 }
718
719 template <typename I>
720 void ImageState<I>::send_prepare_lock_unlock() {
721   CephContext *cct = m_image_ctx->cct;
722   ldout(cct, 10) << this << " " << __func__ << dendl;
723
724   assert(m_lock.is_locked());
725   m_state = STATE_PREPARING_LOCK;
726
727   assert(!m_actions_contexts.empty());
728   ActionContexts &action_contexts(m_actions_contexts.front());
729   assert(action_contexts.first.action_type == ACTION_TYPE_LOCK);
730
731   Context *on_ready = action_contexts.first.on_ready;
732   m_lock.Unlock();
733
734   if (on_ready == nullptr) {
735     complete_action_unlock(STATE_OPEN, 0);
736     return;
737   }
738
739   // wake up the lock handler now that its safe to proceed
740   on_ready->complete(0);
741 }
742
743 } // namespace librbd
744
745 template class librbd::ImageState<librbd::ImageCtx>;