1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "InstanceWatcher.h"
5 #include "include/atomic.h"
6 #include "include/stringify.h"
7 #include "common/debug.h"
8 #include "common/errno.h"
9 #include "cls/rbd/cls_rbd_client.h"
10 #include "librbd/ManagedLock.h"
11 #include "librbd/Utils.h"
12 #include "InstanceReplayer.h"
14 #define dout_context g_ceph_context
15 #define dout_subsys ceph_subsys_rbd_mirror
17 #define dout_prefix *_dout << "rbd::mirror::InstanceWatcher: "
22 using namespace instance_watcher
;
24 using librbd::util::create_async_context_callback
;
25 using librbd::util::create_context_callback
;
26 using librbd::util::create_rados_callback
;
27 using librbd::util::unique_lock_name
;
31 struct C_GetInstances
: public Context
{
32 std::vector
<std::string
> *instance_ids
;
36 C_GetInstances(std::vector
<std::string
> *instance_ids
, Context
*on_finish
)
37 : instance_ids(instance_ids
), on_finish(on_finish
) {
40 void finish(int r
) override
{
41 dout(20) << "C_GetInstances: " << this << " " << __func__
<< ": r=" << r
45 bufferlist::iterator it
= out_bl
.begin();
46 r
= librbd::cls_client::mirror_instances_list_finish(&it
, instance_ids
);
47 } else if (r
== -ENOENT
) {
50 on_finish
->complete(r
);
55 struct C_RemoveInstanceRequest
: public Context
{
56 InstanceWatcher
<I
> instance_watcher
;
59 C_RemoveInstanceRequest(librados::IoCtx
&io_ctx
, ContextWQ
*work_queue
,
60 const std::string
&instance_id
, Context
*on_finish
)
61 : instance_watcher(io_ctx
, work_queue
, nullptr, instance_id
),
62 on_finish(on_finish
) {
66 dout(20) << "C_RemoveInstanceRequest: " << this << " " << __func__
<< dendl
;
68 instance_watcher
.remove(this);
71 void finish(int r
) override
{
72 dout(20) << "C_RemoveInstanceRequest: " << this << " " << __func__
<< ": r="
76 on_finish
->complete(r
);
80 } // anonymous namespace
83 struct InstanceWatcher
<I
>::C_NotifyInstanceRequest
: public Context
{
84 InstanceWatcher
<I
> *instance_watcher
;
85 librbd::watcher::Notifier notifier
;
86 std::string instance_id
;
90 librbd::watcher::NotifyResponse response
;
93 C_NotifyInstanceRequest(InstanceWatcher
<I
> *instance_watcher
,
94 const std::string
&instance_id
, uint64_t request_id
,
95 bufferlist
&&bl
, Context
*on_finish
)
96 : instance_watcher(instance_watcher
),
97 notifier(instance_watcher
->m_work_queue
, instance_watcher
->m_ioctx
,
98 RBD_MIRROR_INSTANCE_PREFIX
+ instance_id
),
99 instance_id(instance_id
), request_id(request_id
), bl(bl
),
100 on_finish(on_finish
) {
101 instance_watcher
->m_notify_op_tracker
.start_op();
102 assert(instance_watcher
->m_lock
.is_locked());
103 auto result
= instance_watcher
->m_notify_ops
.insert(
104 std::make_pair(instance_id
, this)).second
;
109 dout(20) << "C_NotifyInstanceRequest: " << this << " " << __func__
<< dendl
;
111 notifier
.notify(bl
, &response
, this);
115 dout(20) << "C_NotifyInstanceRequest: " << this << " " << __func__
<< dendl
;
120 void finish(int r
) override
{
121 dout(20) << "C_NotifyInstanceRequest: " << this << " " << __func__
<< ": r="
124 if (r
== 0 || r
== -ETIMEDOUT
) {
126 for (auto &it
: response
.acks
) {
127 auto &bl
= it
.second
;
128 if (it
.second
.length() == 0) {
129 dout(20) << "C_NotifyInstanceRequest: " << this << " " << __func__
130 << ": no payload in ack, ignoring" << dendl
;
134 auto iter
= bl
.begin();
135 NotifyAckPayload ack
;
137 if (ack
.instance_id
!= instance_watcher
->get_instance_id()) {
138 derr
<< "C_NotifyInstanceRequest: " << this << " " << __func__
139 << ": ack instance_id (" << ack
.instance_id
<< ") "
140 << "does not match, ignoring" << dendl
;
143 if (ack
.request_id
!= request_id
) {
144 derr
<< "C_NotifyInstanceRequest: " << this << " " << __func__
145 << ": ack request_id (" << ack
.request_id
<< ") "
146 << "does not match, ignoring" << dendl
;
152 } catch (const buffer::error
&err
) {
153 derr
<< "C_NotifyInstanceRequest: " << this << " " << __func__
154 << ": failed to decode ack: " << err
.what() << dendl
;
160 if (r
== -ETIMEDOUT
) {
161 if (canceling
.read()) {
164 derr
<< "C_NotifyInstanceRequest: " << this << " " << __func__
165 << ": resending after timeout" << dendl
;
175 instance_watcher
->m_notify_op_tracker
.finish_op();
176 on_finish
->complete(r
);
178 Mutex::Locker
locker(instance_watcher
->m_lock
);
179 auto result
= instance_watcher
->m_notify_ops
.erase(
180 std::make_pair(instance_id
, this));
185 void complete(int r
) override
{
191 #define dout_prefix *_dout << "rbd::mirror::InstanceWatcher: " \
192 << this << " " << __func__ << ": "
193 template <typename I
>
194 void InstanceWatcher
<I
>::get_instances(librados::IoCtx
&io_ctx
,
195 std::vector
<std::string
> *instance_ids
,
196 Context
*on_finish
) {
197 librados::ObjectReadOperation op
;
198 librbd::cls_client::mirror_instances_list_start(&op
);
199 C_GetInstances
*ctx
= new C_GetInstances(instance_ids
, on_finish
);
200 librados::AioCompletion
*aio_comp
= create_rados_callback(ctx
);
202 int r
= io_ctx
.aio_operate(RBD_MIRROR_LEADER
, aio_comp
, &op
, &ctx
->out_bl
);
207 template <typename I
>
208 void InstanceWatcher
<I
>::remove_instance(librados::IoCtx
&io_ctx
,
209 ContextWQ
*work_queue
,
210 const std::string
&instance_id
,
211 Context
*on_finish
) {
212 auto req
= new C_RemoveInstanceRequest
<I
>(io_ctx
, work_queue
, instance_id
,
217 template <typename I
>
218 InstanceWatcher
<I
> *InstanceWatcher
<I
>::create(
219 librados::IoCtx
&io_ctx
, ContextWQ
*work_queue
,
220 InstanceReplayer
<I
> *instance_replayer
) {
221 return new InstanceWatcher
<I
>(io_ctx
, work_queue
, instance_replayer
,
222 stringify(io_ctx
.get_instance_id()));
225 template <typename I
>
226 InstanceWatcher
<I
>::InstanceWatcher(librados::IoCtx
&io_ctx
,
227 ContextWQ
*work_queue
,
228 InstanceReplayer
<I
> *instance_replayer
,
229 const std::string
&instance_id
)
230 : Watcher(io_ctx
, work_queue
, RBD_MIRROR_INSTANCE_PREFIX
+ instance_id
),
231 m_instance_replayer(instance_replayer
), m_instance_id(instance_id
),
232 m_lock(unique_lock_name("rbd::mirror::InstanceWatcher::m_lock", this)),
233 m_instance_lock(librbd::ManagedLock
<I
>::create(
234 m_ioctx
, m_work_queue
, m_oid
, this, librbd::managed_lock::EXCLUSIVE
, true,
235 m_cct
->_conf
->rbd_blacklist_expire_seconds
)) {
238 template <typename I
>
239 InstanceWatcher
<I
>::~InstanceWatcher() {
240 m_instance_lock
->destroy();
243 template <typename I
>
244 int InstanceWatcher
<I
>::init() {
245 C_SaferCond init_ctx
;
247 return init_ctx
.wait();
250 template <typename I
>
251 void InstanceWatcher
<I
>::init(Context
*on_finish
) {
252 dout(20) << "instance_id=" << m_instance_id
<< dendl
;
254 Mutex::Locker
locker(m_lock
);
256 assert(m_on_finish
== nullptr);
257 m_on_finish
= on_finish
;
263 template <typename I
>
264 void InstanceWatcher
<I
>::shut_down() {
265 C_SaferCond shut_down_ctx
;
266 shut_down(&shut_down_ctx
);
267 int r
= shut_down_ctx
.wait();
271 template <typename I
>
272 void InstanceWatcher
<I
>::shut_down(Context
*on_finish
) {
275 Mutex::Locker
locker(m_lock
);
277 assert(m_on_finish
== nullptr);
278 m_on_finish
= on_finish
;
284 template <typename I
>
285 void InstanceWatcher
<I
>::remove(Context
*on_finish
) {
288 Mutex::Locker
locker(m_lock
);
290 assert(m_on_finish
== nullptr);
291 m_on_finish
= on_finish
;
295 get_instance_locker();
298 template <typename I
>
299 void InstanceWatcher
<I
>::notify_image_acquire(
300 const std::string
&instance_id
, const std::string
&global_image_id
,
301 const std::string
&peer_mirror_uuid
, const std::string
&peer_image_id
,
302 Context
*on_notify_ack
) {
303 dout(20) << "instance_id=" << instance_id
<< ", global_image_id="
304 << global_image_id
<< dendl
;
306 Mutex::Locker
locker(m_lock
);
308 assert(m_on_finish
== nullptr);
310 if (instance_id
== m_instance_id
) {
311 handle_image_acquire(global_image_id
, peer_mirror_uuid
, peer_image_id
,
314 uint64_t request_id
= ++m_request_seq
;
316 ::encode(NotifyMessage
{ImageAcquirePayload
{
317 request_id
, global_image_id
, peer_mirror_uuid
, peer_image_id
}}, bl
);
318 auto req
= new C_NotifyInstanceRequest(this, instance_id
, request_id
,
319 std::move(bl
), on_notify_ack
);
324 template <typename I
>
325 void InstanceWatcher
<I
>::notify_image_release(
326 const std::string
&instance_id
, const std::string
&global_image_id
,
327 const std::string
&peer_mirror_uuid
, const std::string
&peer_image_id
,
328 bool schedule_delete
, Context
*on_notify_ack
) {
329 dout(20) << "instance_id=" << instance_id
<< ", global_image_id="
330 << global_image_id
<< dendl
;
332 Mutex::Locker
locker(m_lock
);
334 assert(m_on_finish
== nullptr);
336 if (instance_id
== m_instance_id
) {
337 handle_image_release(global_image_id
, peer_mirror_uuid
, peer_image_id
,
338 schedule_delete
, on_notify_ack
);
340 uint64_t request_id
= ++m_request_seq
;
342 ::encode(NotifyMessage
{ImageReleasePayload
{
343 request_id
, global_image_id
, peer_mirror_uuid
, peer_image_id
,
344 schedule_delete
}}, bl
);
345 auto req
= new C_NotifyInstanceRequest(this, instance_id
, request_id
,
346 std::move(bl
), on_notify_ack
);
351 template <typename I
>
352 void InstanceWatcher
<I
>::cancel_notify_requests(
353 const std::string
&instance_id
) {
354 dout(20) << "instance_id=" << instance_id
<< dendl
;
356 Mutex::Locker
locker(m_lock
);
358 for (auto op
: m_notify_ops
) {
359 if (op
.first
== instance_id
) {
366 template <typename I
>
367 void InstanceWatcher
<I
>::register_instance() {
368 assert(m_lock
.is_locked());
372 librados::ObjectWriteOperation op
;
373 librbd::cls_client::mirror_instances_add(&op
, m_instance_id
);
374 librados::AioCompletion
*aio_comp
= create_rados_callback
<
375 InstanceWatcher
<I
>, &InstanceWatcher
<I
>::handle_register_instance
>(this);
377 int r
= m_ioctx
.aio_operate(RBD_MIRROR_LEADER
, aio_comp
, &op
);
382 template <typename I
>
383 void InstanceWatcher
<I
>::handle_register_instance(int r
) {
384 dout(20) << "r=" << r
<< dendl
;
386 Context
*on_finish
= nullptr;
388 Mutex::Locker
locker(m_lock
);
391 create_instance_object();
395 derr
<< "error registering instance: " << cpp_strerror(r
) << dendl
;
397 std::swap(on_finish
, m_on_finish
);
399 on_finish
->complete(r
);
403 template <typename I
>
404 void InstanceWatcher
<I
>::create_instance_object() {
407 assert(m_lock
.is_locked());
409 librados::ObjectWriteOperation op
;
412 librados::AioCompletion
*aio_comp
= create_rados_callback
<
414 &InstanceWatcher
<I
>::handle_create_instance_object
>(this);
415 int r
= m_ioctx
.aio_operate(m_oid
, aio_comp
, &op
);
420 template <typename I
>
421 void InstanceWatcher
<I
>::handle_create_instance_object(int r
) {
422 dout(20) << "r=" << r
<< dendl
;
424 Mutex::Locker
locker(m_lock
);
427 derr
<< "error creating " << m_oid
<< " object: " << cpp_strerror(r
)
431 unregister_instance();
438 template <typename I
>
439 void InstanceWatcher
<I
>::register_watch() {
442 assert(m_lock
.is_locked());
444 Context
*ctx
= create_async_context_callback(
445 m_work_queue
, create_context_callback
<
446 InstanceWatcher
<I
>, &InstanceWatcher
<I
>::handle_register_watch
>(this));
448 librbd::Watcher::register_watch(ctx
);
451 template <typename I
>
452 void InstanceWatcher
<I
>::handle_register_watch(int r
) {
453 dout(20) << "r=" << r
<< dendl
;
455 Mutex::Locker
locker(m_lock
);
458 derr
<< "error registering instance watcher for " << m_oid
<< " object: "
459 << cpp_strerror(r
) << dendl
;
462 remove_instance_object();
469 template <typename I
>
470 void InstanceWatcher
<I
>::acquire_lock() {
473 assert(m_lock
.is_locked());
475 Context
*ctx
= create_async_context_callback(
476 m_work_queue
, create_context_callback
<
477 InstanceWatcher
<I
>, &InstanceWatcher
<I
>::handle_acquire_lock
>(this));
479 m_instance_lock
->acquire_lock(ctx
);
482 template <typename I
>
483 void InstanceWatcher
<I
>::handle_acquire_lock(int r
) {
484 dout(20) << "r=" << r
<< dendl
;
486 Context
*on_finish
= nullptr;
488 Mutex::Locker
locker(m_lock
);
492 derr
<< "error acquiring instance lock: " << cpp_strerror(r
) << dendl
;
499 std::swap(on_finish
, m_on_finish
);
502 on_finish
->complete(r
);
505 template <typename I
>
506 void InstanceWatcher
<I
>::release_lock() {
509 assert(m_lock
.is_locked());
511 Context
*ctx
= create_async_context_callback(
512 m_work_queue
, create_context_callback
<
513 InstanceWatcher
<I
>, &InstanceWatcher
<I
>::handle_release_lock
>(this));
515 m_instance_lock
->shut_down(ctx
);
518 template <typename I
>
519 void InstanceWatcher
<I
>::handle_release_lock(int r
) {
520 dout(20) << "r=" << r
<< dendl
;
522 Mutex::Locker
locker(m_lock
);
525 derr
<< "error releasing instance lock: " << cpp_strerror(r
) << dendl
;
531 template <typename I
>
532 void InstanceWatcher
<I
>::unregister_watch() {
535 assert(m_lock
.is_locked());
537 Context
*ctx
= create_async_context_callback(
538 m_work_queue
, create_context_callback
<
539 InstanceWatcher
<I
>, &InstanceWatcher
<I
>::handle_unregister_watch
>(this));
541 librbd::Watcher::unregister_watch(ctx
);
544 template <typename I
>
545 void InstanceWatcher
<I
>::handle_unregister_watch(int r
) {
546 dout(20) << "r=" << r
<< dendl
;
549 derr
<< "error unregistering instance watcher for " << m_oid
<< " object: "
550 << cpp_strerror(r
) << dendl
;
553 Mutex::Locker
locker(m_lock
);
554 remove_instance_object();
557 template <typename I
>
558 void InstanceWatcher
<I
>::remove_instance_object() {
559 assert(m_lock
.is_locked());
563 librados::ObjectWriteOperation op
;
566 librados::AioCompletion
*aio_comp
= create_rados_callback
<
568 &InstanceWatcher
<I
>::handle_remove_instance_object
>(this);
569 int r
= m_ioctx
.aio_operate(m_oid
, aio_comp
, &op
);
574 template <typename I
>
575 void InstanceWatcher
<I
>::handle_remove_instance_object(int r
) {
576 dout(20) << "r=" << r
<< dendl
;
578 if (m_removing
&& r
== -ENOENT
) {
583 derr
<< "error removing " << m_oid
<< " object: " << cpp_strerror(r
)
587 Mutex::Locker
locker(m_lock
);
588 unregister_instance();
591 template <typename I
>
592 void InstanceWatcher
<I
>::unregister_instance() {
595 assert(m_lock
.is_locked());
597 librados::ObjectWriteOperation op
;
598 librbd::cls_client::mirror_instances_remove(&op
, m_instance_id
);
599 librados::AioCompletion
*aio_comp
= create_rados_callback
<
600 InstanceWatcher
<I
>, &InstanceWatcher
<I
>::handle_unregister_instance
>(this);
602 int r
= m_ioctx
.aio_operate(RBD_MIRROR_LEADER
, aio_comp
, &op
);
607 template <typename I
>
608 void InstanceWatcher
<I
>::handle_unregister_instance(int r
) {
609 dout(20) << "r=" << r
<< dendl
;
612 derr
<< "error unregistering instance: " << cpp_strerror(r
) << dendl
;
615 Mutex::Locker
locker(m_lock
);
616 wait_for_notify_ops();
619 template <typename I
>
620 void InstanceWatcher
<I
>::wait_for_notify_ops() {
623 assert(m_lock
.is_locked());
625 for (auto op
: m_notify_ops
) {
629 Context
*ctx
= create_async_context_callback(
630 m_work_queue
, create_context_callback
<
631 InstanceWatcher
<I
>, &InstanceWatcher
<I
>::handle_wait_for_notify_ops
>(this));
633 m_notify_op_tracker
.wait_for_ops(ctx
);
636 template <typename I
>
637 void InstanceWatcher
<I
>::handle_wait_for_notify_ops(int r
) {
638 dout(20) << "r=" << r
<< dendl
;
642 Context
*on_finish
= nullptr;
644 Mutex::Locker
locker(m_lock
);
646 assert(m_notify_ops
.empty());
648 std::swap(on_finish
, m_on_finish
);
655 on_finish
->complete(r
);
658 template <typename I
>
659 void InstanceWatcher
<I
>::get_instance_locker() {
662 assert(m_lock
.is_locked());
664 Context
*ctx
= create_async_context_callback(
665 m_work_queue
, create_context_callback
<
666 InstanceWatcher
<I
>, &InstanceWatcher
<I
>::handle_get_instance_locker
>(this));
668 m_instance_lock
->get_locker(&m_instance_locker
, ctx
);
671 template <typename I
>
672 void InstanceWatcher
<I
>::handle_get_instance_locker(int r
) {
673 dout(20) << "r=" << r
<< dendl
;
675 Mutex::Locker
locker(m_lock
);
679 derr
<< "error retrieving instance locker: " << cpp_strerror(r
) << dendl
;
681 remove_instance_object();
685 break_instance_lock();
688 template <typename I
>
689 void InstanceWatcher
<I
>::break_instance_lock() {
692 assert(m_lock
.is_locked());
694 Context
*ctx
= create_async_context_callback(
695 m_work_queue
, create_context_callback
<
696 InstanceWatcher
<I
>, &InstanceWatcher
<I
>::handle_break_instance_lock
>(this));
698 m_instance_lock
->break_lock(m_instance_locker
, true, ctx
);
701 template <typename I
>
702 void InstanceWatcher
<I
>::handle_break_instance_lock(int r
) {
703 dout(20) << "r=" << r
<< dendl
;
705 Mutex::Locker
locker(m_lock
);
709 derr
<< "error breaking instance lock: " << cpp_strerror(r
) << dendl
;
711 remove_instance_object();
715 remove_instance_object();
718 template <typename I
>
719 Context
*InstanceWatcher
<I
>::prepare_request(const std::string
&instance_id
,
721 C_NotifyAck
*on_notify_ack
) {
722 dout(20) << "instance_id=" << instance_id
<< ", request_id=" << request_id
725 Mutex::Locker
locker(m_lock
);
727 Context
*ctx
= nullptr;
728 Request
request(instance_id
, request_id
);
729 auto it
= m_requests
.find(request
);
731 if (it
!= m_requests
.end()) {
732 dout(20) << "duplicate for in-progress request" << dendl
;
733 delete it
->on_notify_ack
;
734 m_requests
.erase(it
);
736 ctx
= new FunctionContext(
737 [this, instance_id
, request_id
] (int r
) {
738 C_NotifyAck
*on_notify_ack
= nullptr;
740 // update request state in the requests list
741 Mutex::Locker
locker(m_lock
);
742 Request
request(instance_id
, request_id
);
743 auto it
= m_requests
.find(request
);
744 assert(it
!= m_requests
.end());
745 on_notify_ack
= it
->on_notify_ack
;
746 m_requests
.erase(it
);
749 ::encode(NotifyAckPayload(instance_id
, request_id
, r
),
751 on_notify_ack
->complete(0);
755 request
.on_notify_ack
= on_notify_ack
;
756 m_requests
.insert(request
);
760 template <typename I
>
761 void InstanceWatcher
<I
>::handle_notify(uint64_t notify_id
, uint64_t handle
,
762 uint64_t notifier_id
, bufferlist
&bl
) {
763 dout(20) << "notify_id=" << notify_id
<< ", handle=" << handle
<< ", "
764 << "notifier_id=" << notifier_id
<< dendl
;
766 auto ctx
= new C_NotifyAck(this, notify_id
, handle
);
768 NotifyMessage notify_message
;
770 bufferlist::iterator iter
= bl
.begin();
771 ::decode(notify_message
, iter
);
772 } catch (const buffer::error
&err
) {
773 derr
<< "error decoding image notification: " << err
.what() << dendl
;
778 apply_visitor(HandlePayloadVisitor(this, stringify(notifier_id
), ctx
),
779 notify_message
.payload
);
782 template <typename I
>
783 void InstanceWatcher
<I
>::handle_image_acquire(
784 const std::string
&global_image_id
, const std::string
&peer_mirror_uuid
,
785 const std::string
&peer_image_id
, Context
*on_finish
) {
786 dout(20) << "global_image_id=" << global_image_id
<< dendl
;
788 m_instance_replayer
->acquire_image(global_image_id
, peer_mirror_uuid
,
789 peer_image_id
, on_finish
);
792 template <typename I
>
793 void InstanceWatcher
<I
>::handle_image_release(
794 const std::string
&global_image_id
, const std::string
&peer_mirror_uuid
,
795 const std::string
&peer_image_id
, bool schedule_delete
, Context
*on_finish
) {
796 dout(20) << "global_image_id=" << global_image_id
<< dendl
;
798 m_instance_replayer
->release_image(global_image_id
, peer_mirror_uuid
,
799 peer_image_id
, schedule_delete
, on_finish
);
802 template <typename I
>
803 void InstanceWatcher
<I
>::handle_payload(const std::string
&instance_id
,
804 const ImageAcquirePayload
&payload
,
805 C_NotifyAck
*on_notify_ack
) {
806 dout(20) << "image_acquire: instance_id=" << instance_id
<< ", "
807 << "request_id=" << payload
.request_id
<< dendl
;
809 auto on_finish
= prepare_request(instance_id
, payload
.request_id
,
811 if (on_finish
!= nullptr) {
812 handle_image_acquire(payload
.global_image_id
, payload
.peer_mirror_uuid
,
813 payload
.peer_image_id
, on_finish
);
817 template <typename I
>
818 void InstanceWatcher
<I
>::handle_payload(const std::string
&instance_id
,
819 const ImageReleasePayload
&payload
,
820 C_NotifyAck
*on_notify_ack
) {
821 dout(20) << "image_release: instance_id=" << instance_id
<< ", "
822 << "request_id=" << payload
.request_id
<< dendl
;
824 auto on_finish
= prepare_request(instance_id
, payload
.request_id
,
826 if (on_finish
!= nullptr) {
827 handle_image_release(payload
.global_image_id
, payload
.peer_mirror_uuid
,
828 payload
.peer_image_id
, payload
.schedule_delete
,
833 template <typename I
>
834 void InstanceWatcher
<I
>::handle_payload(const std::string
&instance_id
,
835 const UnknownPayload
&payload
,
836 C_NotifyAck
*on_notify_ack
) {
837 dout(20) << "unknown: instance_id=" << instance_id
<< dendl
;
839 on_notify_ack
->complete(0);
842 } // namespace mirror
845 template class rbd::mirror::InstanceWatcher
<librbd::ImageCtx
>;