1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "RemotePoolPoller.h"
5 #include "include/ceph_assert.h"
6 #include "common/debug.h"
7 #include "common/errno.h"
8 #include "common/Timer.h"
9 #include "cls/rbd/cls_rbd_client.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/Utils.h"
12 #include "librbd/asio/ContextWQ.h"
13 #include "tools/rbd_mirror/Threads.h"
14 #include "tools/rbd_mirror/Types.h"
16 #define dout_context g_ceph_context
17 #define dout_subsys ceph_subsys_rbd_mirror
19 #define dout_prefix *_dout << "rbd::mirror::RemotePollPoller: " << this << " " \
25 static const double POLL_INTERVAL_SECONDS
= 30;
27 using librbd::util::create_rados_callback
;
30 RemotePoolPoller
<I
>::~RemotePoolPoller() {
31 ceph_assert(m_timer_task
== nullptr);
35 void RemotePoolPoller
<I
>::init(Context
* on_finish
) {
38 ceph_assert(m_state
== STATE_INITIALIZING
);
39 ceph_assert(m_on_finish
== nullptr);
40 m_on_finish
= on_finish
;
46 void RemotePoolPoller
<I
>::shut_down(Context
* on_finish
) {
49 std::unique_lock
locker(m_threads
->timer_lock
);
50 ceph_assert(m_state
== STATE_POLLING
);
51 m_state
= STATE_SHUTTING_DOWN
;
53 if (m_timer_task
== nullptr) {
54 // currently executing a poll
55 ceph_assert(m_on_finish
== nullptr);
56 m_on_finish
= on_finish
;
60 m_threads
->timer
->cancel_event(m_timer_task
);
61 m_timer_task
= nullptr;
62 m_threads
->work_queue
->queue(on_finish
, 0);
66 void RemotePoolPoller
<I
>::get_mirror_uuid() {
69 librados::ObjectReadOperation op
;
70 librbd::cls_client::mirror_uuid_get_start(&op
);
72 auto aio_comp
= create_rados_callback
<
73 RemotePoolPoller
<I
>, &RemotePoolPoller
<I
>::handle_get_mirror_uuid
>(this);
75 int r
= m_remote_io_ctx
.aio_operate(RBD_MIRRORING
, aio_comp
, &op
, &m_out_bl
);
81 void RemotePoolPoller
<I
>::handle_get_mirror_uuid(int r
) {
82 dout(10) << "r=" << r
<< dendl
;
83 std::string remote_mirror_uuid
;
85 auto it
= m_out_bl
.cbegin();
86 r
= librbd::cls_client::mirror_uuid_get_finish(&it
, &remote_mirror_uuid
);
87 if (r
>= 0 && remote_mirror_uuid
.empty()) {
94 dout(5) << "remote mirror uuid missing" << dendl
;
96 derr
<< "failed to retrieve remote mirror uuid: " << cpp_strerror(r
)
100 m_remote_pool_meta
.mirror_uuid
= "";
103 // if we have the mirror uuid, we will poll until shut down
104 if (m_state
== STATE_INITIALIZING
) {
110 m_state
= STATE_POLLING
;
113 dout(10) << "remote_mirror_uuid=" << remote_mirror_uuid
<< dendl
;
114 if (m_remote_pool_meta
.mirror_uuid
!= remote_mirror_uuid
) {
115 m_remote_pool_meta
.mirror_uuid
= remote_mirror_uuid
;
122 template <typename I
>
123 void RemotePoolPoller
<I
>::mirror_peer_ping() {
126 librados::ObjectWriteOperation op
;
127 librbd::cls_client::mirror_peer_ping(&op
, m_site_name
, m_local_mirror_uuid
);
129 auto aio_comp
= create_rados_callback
<
130 RemotePoolPoller
<I
>, &RemotePoolPoller
<I
>::handle_mirror_peer_ping
>(this);
131 int r
= m_remote_io_ctx
.aio_operate(RBD_MIRRORING
, aio_comp
, &op
);
136 template <typename I
>
137 void RemotePoolPoller
<I
>::handle_mirror_peer_ping(int r
) {
138 dout(10) << "r=" << r
<< dendl
;
140 if (r
== -EOPNOTSUPP
) {
141 // older OSD that doesn't support snaphot-based mirroring, so no need
142 // to query remote peers
143 dout(10) << "remote peer does not support snapshot-based mirroring"
148 // we can still see if we can perform a peer list and find outselves
149 derr
<< "failed to ping remote mirror peer: " << cpp_strerror(r
) << dendl
;
155 template <typename I
>
156 void RemotePoolPoller
<I
>::mirror_peer_list() {
159 librados::ObjectReadOperation op
;
160 librbd::cls_client::mirror_peer_list_start(&op
);
162 auto aio_comp
= create_rados_callback
<
163 RemotePoolPoller
<I
>, &RemotePoolPoller
<I
>::handle_mirror_peer_list
>(this);
165 int r
= m_remote_io_ctx
.aio_operate(RBD_MIRRORING
, aio_comp
, &op
, &m_out_bl
);
170 template <typename I
>
171 void RemotePoolPoller
<I
>::handle_mirror_peer_list(int r
) {
172 dout(10) << "r=" << r
<< dendl
;
174 std::vector
<cls::rbd::MirrorPeer
> peers
;
176 auto iter
= m_out_bl
.cbegin();
177 r
= librbd::cls_client::mirror_peer_list_finish(&iter
, &peers
);
181 derr
<< "failed to retrieve mirror peers: " << cpp_strerror(r
) << dendl
;
184 cls::rbd::MirrorPeer
* matched_peer
= nullptr;
185 for (auto& peer
: peers
) {
186 if (peer
.mirror_peer_direction
== cls::rbd::MIRROR_PEER_DIRECTION_TX
) {
190 if (peer
.mirror_uuid
== m_local_mirror_uuid
) {
191 matched_peer
= &peer
;
193 } else if (peer
.site_name
== m_site_name
) {
194 // keep searching in case we hit an exact match by fsid
195 matched_peer
= &peer
;
199 // older OSDs don't support peer ping so we might fail to find a match,
200 // which will prevent snapshot mirroring from functioning
201 std::string remote_mirror_peer_uuid
;
202 if (matched_peer
!= nullptr) {
203 remote_mirror_peer_uuid
= matched_peer
->uuid
;
206 dout(10) << "remote_mirror_peer_uuid=" << remote_mirror_peer_uuid
<< dendl
;
207 if (m_remote_pool_meta
.mirror_peer_uuid
!= remote_mirror_peer_uuid
) {
208 m_remote_pool_meta
.mirror_peer_uuid
= remote_mirror_peer_uuid
;
215 template <typename I
>
216 void RemotePoolPoller
<I
>::notify_listener() {
217 bool updated
= false;
218 std::swap(updated
, m_updated
);
221 m_listener
.handle_updated(m_remote_pool_meta
);
227 template <typename I
>
228 void RemotePoolPoller
<I
>::schedule_task(int r
) {
229 std::unique_lock locker
{m_threads
->timer_lock
};
231 if (m_state
== STATE_POLLING
) {
234 ceph_assert(m_timer_task
== nullptr);
235 m_timer_task
= new LambdaContext([this](int) {
239 m_threads
->timer
->add_event_after(POLL_INTERVAL_SECONDS
, m_timer_task
);
242 // finish init or shut down callback
243 if (m_on_finish
!= nullptr) {
245 Context
* on_finish
= nullptr;
246 std::swap(on_finish
, m_on_finish
);
247 on_finish
->complete(m_state
== STATE_SHUTTING_DOWN
? 0 : r
);
251 template <typename I
>
252 void RemotePoolPoller
<I
>::handle_task() {
255 ceph_assert(ceph_mutex_is_locked_by_me(m_threads
->timer_lock
));
256 m_timer_task
= nullptr;
258 auto ctx
= new LambdaContext([this](int) {
261 m_threads
->work_queue
->queue(ctx
);
264 } // namespace mirror
267 template class rbd::mirror::RemotePoolPoller
<librbd::ImageCtx
>;