]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd_mirror/image_replayer/PrepareRemoteImageRequest.cc
import ceph 16.2.7
[ceph.git] / ceph / src / tools / rbd_mirror / image_replayer / PrepareRemoteImageRequest.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 "tools/rbd_mirror/image_replayer/PrepareRemoteImageRequest.h"
5 #include "include/rados/librados.hpp"
6 #include "cls/rbd/cls_rbd_client.h"
7 #include "common/debug.h"
8 #include "common/errno.h"
9 #include "journal/Journaler.h"
10 #include "journal/Settings.h"
11 #include "librbd/ImageCtx.h"
12 #include "librbd/Journal.h"
13 #include "librbd/Utils.h"
14 #include "librbd/asio/ContextWQ.h"
15 #include "librbd/mirror/GetInfoRequest.h"
16 #include "tools/rbd_mirror/Threads.h"
17 #include "tools/rbd_mirror/image_replayer/GetMirrorImageIdRequest.h"
18 #include "tools/rbd_mirror/image_replayer/Utils.h"
19 #include "tools/rbd_mirror/image_replayer/journal/StateBuilder.h"
20 #include "tools/rbd_mirror/image_replayer/snapshot/StateBuilder.h"
21
22 #define dout_context g_ceph_context
23 #define dout_subsys ceph_subsys_rbd_mirror
24 #undef dout_prefix
25 #define dout_prefix *_dout << "rbd::mirror::image_replayer::" \
26 << "PrepareRemoteImageRequest: " << this << " " \
27 << __func__ << ": "
28
29 namespace rbd {
30 namespace mirror {
31 namespace image_replayer {
32
33 using librbd::util::create_async_context_callback;
34 using librbd::util::create_context_callback;
35 using librbd::util::create_rados_callback;
36
37 template <typename I>
38 void PrepareRemoteImageRequest<I>::send() {
39 if (*m_state_builder != nullptr) {
40 (*m_state_builder)->remote_mirror_uuid = m_remote_pool_meta.mirror_uuid;
41 }
42
43 get_remote_image_id();
44 }
45
46 template <typename I>
47 void PrepareRemoteImageRequest<I>::get_remote_image_id() {
48 dout(10) << dendl;
49
50 Context *ctx = create_context_callback<
51 PrepareRemoteImageRequest<I>,
52 &PrepareRemoteImageRequest<I>::handle_get_remote_image_id>(this);
53 auto req = GetMirrorImageIdRequest<I>::create(m_remote_io_ctx,
54 m_global_image_id,
55 &m_remote_image_id, ctx);
56 req->send();
57 }
58
59 template <typename I>
60 void PrepareRemoteImageRequest<I>::handle_get_remote_image_id(int r) {
61 dout(10) << "r=" << r << ", "
62 << "remote_image_id=" << m_remote_image_id << dendl;
63
64 if (r == -ENOENT) {
65 finalize_snapshot_state_builder(r);
66 finish(r);
67 return;
68 } else if (r < 0) {
69 finish(r);
70 return;
71 }
72
73 get_mirror_info();
74 }
75
76 template <typename I>
77 void PrepareRemoteImageRequest<I>::get_mirror_info() {
78 dout(10) << dendl;
79
80 auto ctx = create_context_callback<
81 PrepareRemoteImageRequest<I>,
82 &PrepareRemoteImageRequest<I>::handle_get_mirror_info>(this);
83 auto req = librbd::mirror::GetInfoRequest<I>::create(
84 m_remote_io_ctx, m_threads->work_queue, m_remote_image_id,
85 &m_mirror_image, &m_promotion_state, &m_primary_mirror_uuid,
86 ctx);
87 req->send();
88 }
89
90 template <typename I>
91 void PrepareRemoteImageRequest<I>::handle_get_mirror_info(int r) {
92 dout(10) << "r=" << r << dendl;
93
94 if (r == -ENOENT) {
95 dout(10) << "image " << m_global_image_id << " not mirrored" << dendl;
96 finalize_snapshot_state_builder(r);
97 finish(r);
98 return;
99 } else if (r < 0) {
100 derr << "failed to retrieve mirror image details for image "
101 << m_global_image_id << ": " << cpp_strerror(r) << dendl;
102 finish(r);
103 return;
104 }
105
106 auto state_builder = *m_state_builder;
107 if (state_builder != nullptr &&
108 state_builder->get_mirror_image_mode() != m_mirror_image.mode) {
109 derr << "local and remote mirror image using different mirroring modes "
110 << "for image " << m_global_image_id << ": split-brain" << dendl;
111 finish(-EEXIST);
112 return;
113 } else if (m_mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_DISABLING) {
114 dout(5) << "remote image mirroring is being disabled" << dendl;
115 finish(-ENOENT);
116 return;
117 } else if (m_promotion_state != librbd::mirror::PROMOTION_STATE_PRIMARY &&
118 (state_builder == nullptr ||
119 state_builder->local_image_id.empty() ||
120 state_builder->local_promotion_state ==
121 librbd::mirror::PROMOTION_STATE_UNKNOWN)) {
122 // no local image and remote isn't primary -- don't sync it
123 dout(5) << "remote image is not primary -- not syncing" << dendl;
124 finish(-EREMOTEIO);
125 return;
126 }
127
128 switch (m_mirror_image.mode) {
129 case cls::rbd::MIRROR_IMAGE_MODE_JOURNAL:
130 get_client();
131 break;
132 case cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT:
133 finalize_snapshot_state_builder(0);
134 finish(0);
135 break;
136 default:
137 derr << "unsupported mirror image mode " << m_mirror_image.mode << " "
138 << "for image " << m_global_image_id << dendl;
139 finish(-EOPNOTSUPP);
140 break;
141 }
142 }
143
144 template <typename I>
145 void PrepareRemoteImageRequest<I>::get_client() {
146 dout(10) << dendl;
147
148 auto cct = static_cast<CephContext *>(m_local_io_ctx.cct());
149 ::journal::Settings journal_settings;
150 journal_settings.commit_interval = cct->_conf.get_val<double>(
151 "rbd_mirror_journal_commit_age");
152
153 // TODO use Journal thread pool for journal ops until converted to ASIO
154 ContextWQ* context_wq;
155 librbd::Journal<>::get_work_queue(cct, &context_wq);
156
157 ceph_assert(m_remote_journaler == nullptr);
158 m_remote_journaler = new Journaler(context_wq, m_threads->timer,
159 &m_threads->timer_lock, m_remote_io_ctx,
160 m_remote_image_id, m_local_mirror_uuid,
161 journal_settings, m_cache_manager_handler);
162
163 Context *ctx = create_async_context_callback(
164 m_threads->work_queue, create_context_callback<
165 PrepareRemoteImageRequest<I>,
166 &PrepareRemoteImageRequest<I>::handle_get_client>(this));
167 m_remote_journaler->get_client(m_local_mirror_uuid, &m_client, ctx);
168 }
169
170 template <typename I>
171 void PrepareRemoteImageRequest<I>::handle_get_client(int r) {
172 dout(10) << "r=" << r << dendl;
173
174 MirrorPeerClientMeta client_meta;
175 if (r == -ENOENT) {
176 dout(10) << "client not registered" << dendl;
177 register_client();
178 } else if (r < 0) {
179 derr << "failed to retrieve client: " << cpp_strerror(r) << dendl;
180 finish(r);
181 } else if (!util::decode_client_meta(m_client, &client_meta)) {
182 // require operator intervention since the data is corrupt
183 finish(-EBADMSG);
184 } else {
185 // skip registration if it already exists
186 finalize_journal_state_builder(m_client.state, client_meta);
187 finish(0);
188 }
189 }
190
191 template <typename I>
192 void PrepareRemoteImageRequest<I>::register_client() {
193 dout(10) << dendl;
194
195 auto state_builder = *m_state_builder;
196 librbd::journal::MirrorPeerClientMeta client_meta{
197 (state_builder == nullptr ? "" : state_builder->local_image_id)};
198 client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
199
200 librbd::journal::ClientData client_data{client_meta};
201 bufferlist client_data_bl;
202 encode(client_data, client_data_bl);
203
204 Context *ctx = create_async_context_callback(
205 m_threads->work_queue, create_context_callback<
206 PrepareRemoteImageRequest<I>,
207 &PrepareRemoteImageRequest<I>::handle_register_client>(this));
208 m_remote_journaler->register_client(client_data_bl, ctx);
209 }
210
211 template <typename I>
212 void PrepareRemoteImageRequest<I>::handle_register_client(int r) {
213 dout(10) << "r=" << r << dendl;
214
215 if (r < 0) {
216 derr << "failed to register with remote journal: " << cpp_strerror(r)
217 << dendl;
218 finish(r);
219 return;
220 }
221
222 auto state_builder = *m_state_builder;
223 librbd::journal::MirrorPeerClientMeta client_meta{
224 (state_builder == nullptr ? "" : state_builder->local_image_id)};
225 client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
226 finalize_journal_state_builder(cls::journal::CLIENT_STATE_CONNECTED,
227 client_meta);
228 finish(0);
229 }
230
231 template <typename I>
232 void PrepareRemoteImageRequest<I>::finalize_journal_state_builder(
233 cls::journal::ClientState client_state,
234 const MirrorPeerClientMeta& client_meta) {
235 journal::StateBuilder<I>* state_builder = nullptr;
236 if (*m_state_builder != nullptr) {
237 // already verified that it's a matching builder in
238 // 'handle_get_mirror_info'
239 state_builder = dynamic_cast<journal::StateBuilder<I>*>(*m_state_builder);
240 ceph_assert(state_builder != nullptr);
241 } else {
242 state_builder = journal::StateBuilder<I>::create(m_global_image_id);
243 *m_state_builder = state_builder;
244 }
245
246 state_builder->remote_mirror_uuid = m_remote_pool_meta.mirror_uuid;
247 state_builder->remote_image_id = m_remote_image_id;
248 state_builder->remote_promotion_state = m_promotion_state;
249 state_builder->remote_journaler = m_remote_journaler;
250 state_builder->remote_client_state = client_state;
251 state_builder->remote_client_meta = client_meta;
252 }
253
254 template <typename I>
255 void PrepareRemoteImageRequest<I>::finalize_snapshot_state_builder(int r) {
256 snapshot::StateBuilder<I>* state_builder = nullptr;
257 if (*m_state_builder != nullptr) {
258 state_builder = dynamic_cast<snapshot::StateBuilder<I>*>(*m_state_builder);
259 } else if (r >= 0) {
260 state_builder = snapshot::StateBuilder<I>::create(m_global_image_id);
261 *m_state_builder = state_builder;
262 }
263
264 if (state_builder == nullptr) {
265 // local image prepare failed or is using journal-based mirroring
266 return;
267 }
268
269 dout(10) << "remote_mirror_uuid=" << m_remote_pool_meta.mirror_uuid << ", "
270 << "remote_mirror_peer_uuid="
271 << m_remote_pool_meta.mirror_peer_uuid << ", "
272 << "remote_image_id=" << m_remote_image_id << ", "
273 << "remote_promotion_state=" << m_promotion_state << dendl;
274 ceph_assert(state_builder != nullptr);
275 state_builder->remote_mirror_uuid = m_remote_pool_meta.mirror_uuid;
276 state_builder->remote_mirror_peer_uuid = m_remote_pool_meta.mirror_peer_uuid;
277 state_builder->remote_image_id = m_remote_image_id;
278 state_builder->remote_promotion_state = m_promotion_state;
279 }
280
281 template <typename I>
282 void PrepareRemoteImageRequest<I>::finish(int r) {
283 dout(10) << "r=" << r << dendl;
284
285 if (r < 0) {
286 delete m_remote_journaler;
287 m_remote_journaler = nullptr;
288 }
289
290 m_on_finish->complete(r);
291 delete this;
292 }
293
294 } // namespace image_replayer
295 } // namespace mirror
296 } // namespace rbd
297
298 template class rbd::mirror::image_replayer::PrepareRemoteImageRequest<librbd::ImageCtx>;