]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd_mirror/RemotePoolPoller.cc
import ceph 15.2.15
[ceph.git] / ceph / src / tools / rbd_mirror / RemotePoolPoller.cc
CommitLineData
9f95a23c
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
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 "common/WorkQueue.h"
10#include "cls/rbd/cls_rbd_client.h"
11#include "librbd/ImageCtx.h"
12#include "librbd/Utils.h"
13#include "tools/rbd_mirror/Threads.h"
14#include "tools/rbd_mirror/Types.h"
15
16#define dout_context g_ceph_context
17#define dout_subsys ceph_subsys_rbd_mirror
18#undef dout_prefix
dc7c3f34 19#define dout_prefix *_dout << "rbd::mirror::RemotePoolPoller: " << this << " " \
9f95a23c
TL
20 << __func__ << ": "
21
22namespace rbd {
23namespace mirror {
24
25static const double POLL_INTERVAL_SECONDS = 30;
26
27using librbd::util::create_rados_callback;
28
29template <typename I>
30RemotePoolPoller<I>::~RemotePoolPoller() {
31 ceph_assert(m_timer_task == nullptr);
32}
33
34template <typename I>
35void RemotePoolPoller<I>::init(Context* on_finish) {
36 dout(10) << dendl;
37
38 ceph_assert(m_state == STATE_INITIALIZING);
39 ceph_assert(m_on_finish == nullptr);
40 m_on_finish = on_finish;
41
42 get_mirror_uuid();
43}
44
45template <typename I>
46void RemotePoolPoller<I>::shut_down(Context* on_finish) {
47 dout(10) << dendl;
48
49 std::unique_lock locker(m_threads->timer_lock);
50 ceph_assert(m_state == STATE_POLLING);
51 m_state = STATE_SHUTTING_DOWN;
52
53 if (m_timer_task == nullptr) {
54 // currently executing a poll
55 ceph_assert(m_on_finish == nullptr);
56 m_on_finish = on_finish;
57 return;
58 }
59
60 m_threads->timer->cancel_event(m_timer_task);
61 m_timer_task = nullptr;
62 m_threads->work_queue->queue(on_finish, 0);
63}
64
65template <typename I>
66void RemotePoolPoller<I>::get_mirror_uuid() {
67 dout(10) << dendl;
68
69 librados::ObjectReadOperation op;
70 librbd::cls_client::mirror_uuid_get_start(&op);
71
72 auto aio_comp = create_rados_callback<
73 RemotePoolPoller<I>, &RemotePoolPoller<I>::handle_get_mirror_uuid>(this);
74 m_out_bl.clear();
75 int r = m_remote_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, &m_out_bl);
76 ceph_assert(r == 0);
77 aio_comp->release();
78}
79
80template <typename I>
81void RemotePoolPoller<I>::handle_get_mirror_uuid(int r) {
82 dout(10) << "r=" << r << dendl;
83 std::string remote_mirror_uuid;
84 if (r >= 0) {
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()) {
88 r = -ENOENT;
89 }
90 }
91
92 if (r < 0) {
93 if (r == -ENOENT) {
94 dout(5) << "remote mirror uuid missing" << dendl;
95 } else {
96 derr << "failed to retrieve remote mirror uuid: " << cpp_strerror(r)
97 << dendl;
98 }
99
100 m_remote_pool_meta.mirror_uuid = "";
101 }
102
103 // if we have the mirror uuid, we will poll until shut down
104 if (m_state == STATE_INITIALIZING) {
105 if (r < 0) {
106 schedule_task(r);
107 return;
108 }
109
110 m_state = STATE_POLLING;
111 }
112
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;
116 m_updated = true;
117 }
118
119 mirror_peer_ping();
120}
121
122template <typename I>
123void RemotePoolPoller<I>::mirror_peer_ping() {
124 dout(10) << dendl;
125
126 librados::ObjectWriteOperation op;
127 librbd::cls_client::mirror_peer_ping(&op, m_site_name, m_local_mirror_uuid);
128
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);
132 ceph_assert(r == 0);
133 aio_comp->release();
134}
135
136template <typename I>
137void RemotePoolPoller<I>::handle_mirror_peer_ping(int r) {
138 dout(10) << "r=" << r << dendl;
139
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"
144 << dendl;
145 notify_listener();
146 return;
147 } else if (r < 0) {
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;
150 }
151
152 mirror_peer_list();
153}
154
155template <typename I>
156void RemotePoolPoller<I>::mirror_peer_list() {
157 dout(10) << dendl;
158
159 librados::ObjectReadOperation op;
160 librbd::cls_client::mirror_peer_list_start(&op);
161
162 auto aio_comp = create_rados_callback<
163 RemotePoolPoller<I>, &RemotePoolPoller<I>::handle_mirror_peer_list>(this);
164 m_out_bl.clear();
165 int r = m_remote_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, &m_out_bl);
166 ceph_assert(r == 0);
167 aio_comp->release();
168}
169
170template <typename I>
171void RemotePoolPoller<I>::handle_mirror_peer_list(int r) {
172 dout(10) << "r=" << r << dendl;
173
174 std::vector<cls::rbd::MirrorPeer> peers;
175 if (r == 0) {
176 auto iter = m_out_bl.cbegin();
177 r = librbd::cls_client::mirror_peer_list_finish(&iter, &peers);
178 }
179
180 if (r < 0) {
181 derr << "failed to retrieve mirror peers: " << cpp_strerror(r) << dendl;
182 }
183
184 cls::rbd::MirrorPeer* matched_peer = nullptr;
185 for (auto& peer : peers) {
dc7c3f34 186 if (peer.mirror_peer_direction == cls::rbd::MIRROR_PEER_DIRECTION_RX) {
9f95a23c
TL
187 continue;
188 }
189
190 if (peer.mirror_uuid == m_local_mirror_uuid) {
191 matched_peer = &peer;
192 break;
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;
196 }
197 }
198
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;
204 }
205
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;
209 m_updated = true;
210 }
211
212 notify_listener();
213}
214
215template <typename I>
216void RemotePoolPoller<I>::notify_listener() {
217 bool updated = false;
218 std::swap(updated, m_updated);
219 if (updated) {
220 dout(10) << dendl;
221 m_listener.handle_updated(m_remote_pool_meta);
222 }
223
224 schedule_task(0);
225}
226
227template <typename I>
228void RemotePoolPoller<I>::schedule_task(int r) {
229 std::unique_lock locker{m_threads->timer_lock};
230
231 if (m_state == STATE_POLLING) {
232 dout(10) << dendl;
233
234 ceph_assert(m_timer_task == nullptr);
235 m_timer_task = new LambdaContext([this](int) {
236 handle_task();
237 });
238
239 m_threads->timer->add_event_after(POLL_INTERVAL_SECONDS, m_timer_task);
240 }
241
242 // finish init or shut down callback
243 if (m_on_finish != nullptr) {
244 locker.unlock();
245 Context* on_finish = nullptr;
246 std::swap(on_finish, m_on_finish);
247 on_finish->complete(m_state == STATE_SHUTTING_DOWN ? 0 : r);
248 }
249}
250
251template <typename I>
252void RemotePoolPoller<I>::handle_task() {
253 dout(10) << dendl;
254
255 ceph_assert(ceph_mutex_is_locked_by_me(m_threads->timer_lock));
256 m_timer_task = nullptr;
257
258 auto ctx = new LambdaContext([this](int) {
259 get_mirror_uuid();
260 });
261 m_threads->work_queue->queue(ctx);
262}
263
264} // namespace mirror
265} // namespace rbd
266
267template class rbd::mirror::RemotePoolPoller<librbd::ImageCtx>;