]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "CreateImageRequest.h" | |
5 | #include "CloseImageRequest.h" | |
6 | #include "OpenImageRequest.h" | |
7 | #include "common/errno.h" | |
8 | #include "common/WorkQueue.h" | |
9 | #include "cls/rbd/cls_rbd_client.h" | |
10 | #include "librbd/ImageCtx.h" | |
11 | #include "librbd/ImageState.h" | |
12 | #include "librbd/internal.h" | |
13 | #include "librbd/Utils.h" | |
14 | #include "librbd/image/CreateRequest.h" | |
15 | #include "librbd/image/CloneRequest.h" | |
16 | ||
17 | #define dout_context g_ceph_context | |
18 | #define dout_subsys ceph_subsys_rbd_mirror | |
19 | #undef dout_prefix | |
20 | #define dout_prefix *_dout << "rbd::mirror::image_replayer::CreateImageRequest: " \ | |
21 | << this << " " << __func__ | |
22 | ||
23 | using librbd::util::create_context_callback; | |
24 | using librbd::util::create_rados_callback; | |
25 | ||
26 | namespace rbd { | |
27 | namespace mirror { | |
28 | namespace image_replayer { | |
29 | ||
30 | template <typename I> | |
31 | CreateImageRequest<I>::CreateImageRequest(librados::IoCtx &local_io_ctx, | |
32 | ContextWQ *work_queue, | |
33 | const std::string &global_image_id, | |
34 | const std::string &remote_mirror_uuid, | |
35 | const std::string &local_image_name, | |
d2e6a577 | 36 | const std::string &local_image_id, |
7c673cae | 37 | I *remote_image_ctx, |
7c673cae FG |
38 | Context *on_finish) |
39 | : m_local_io_ctx(local_io_ctx), m_work_queue(work_queue), | |
40 | m_global_image_id(global_image_id), | |
41 | m_remote_mirror_uuid(remote_mirror_uuid), | |
d2e6a577 FG |
42 | m_local_image_name(local_image_name), m_local_image_id(local_image_id), |
43 | m_remote_image_ctx(remote_image_ctx), m_on_finish(on_finish) { | |
7c673cae FG |
44 | } |
45 | ||
46 | template <typename I> | |
47 | void CreateImageRequest<I>::send() { | |
48 | int r = validate_parent(); | |
49 | if (r < 0) { | |
50 | error(r); | |
51 | return; | |
52 | } | |
53 | ||
54 | if (m_remote_parent_spec.pool_id == -1) { | |
55 | create_image(); | |
56 | } else { | |
57 | get_parent_global_image_id(); | |
58 | } | |
59 | } | |
60 | ||
61 | template <typename I> | |
62 | void CreateImageRequest<I>::create_image() { | |
63 | dout(20) << dendl; | |
64 | ||
65 | using klass = CreateImageRequest<I>; | |
66 | Context *ctx = create_context_callback<klass, &klass::handle_create_image>(this); | |
67 | ||
68 | RWLock::RLocker snap_locker(m_remote_image_ctx->snap_lock); | |
69 | ||
70 | librbd::ImageOptions image_options; | |
71 | image_options.set(RBD_IMAGE_OPTION_FEATURES, m_remote_image_ctx->features); | |
72 | image_options.set(RBD_IMAGE_OPTION_ORDER, m_remote_image_ctx->order); | |
73 | image_options.set(RBD_IMAGE_OPTION_STRIPE_UNIT, | |
74 | m_remote_image_ctx->stripe_unit); | |
75 | image_options.set(RBD_IMAGE_OPTION_STRIPE_COUNT, | |
76 | m_remote_image_ctx->stripe_count); | |
77 | ||
7c673cae | 78 | librbd::image::CreateRequest<I> *req = librbd::image::CreateRequest<I>::create( |
d2e6a577 | 79 | m_local_io_ctx, m_local_image_name, m_local_image_id, |
7c673cae FG |
80 | m_remote_image_ctx->size, image_options, m_global_image_id, |
81 | m_remote_mirror_uuid, false, m_remote_image_ctx->op_work_queue, ctx); | |
82 | req->send(); | |
83 | } | |
84 | ||
85 | template <typename I> | |
86 | void CreateImageRequest<I>::handle_create_image(int r) { | |
87 | dout(20) << ": r=" << r << dendl; | |
88 | if (r < 0) { | |
89 | derr << ": failed to create local image: " << cpp_strerror(r) << dendl; | |
90 | finish(r); | |
91 | return; | |
92 | } | |
93 | ||
94 | finish(0); | |
95 | } | |
96 | ||
97 | template <typename I> | |
98 | void CreateImageRequest<I>::get_parent_global_image_id() { | |
99 | dout(20) << dendl; | |
100 | ||
101 | librados::ObjectReadOperation op; | |
102 | librbd::cls_client::mirror_image_get_start(&op, m_remote_parent_spec.image_id); | |
103 | ||
104 | librados::AioCompletion *aio_comp = create_rados_callback< | |
105 | CreateImageRequest<I>, | |
106 | &CreateImageRequest<I>::handle_get_parent_global_image_id>(this); | |
107 | m_out_bl.clear(); | |
108 | int r = m_remote_parent_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, | |
109 | &m_out_bl); | |
110 | assert(r == 0); | |
111 | aio_comp->release(); | |
112 | } | |
113 | ||
114 | template <typename I> | |
115 | void CreateImageRequest<I>::handle_get_parent_global_image_id(int r) { | |
116 | dout(20) << ": r=" << r << dendl; | |
117 | if (r == 0) { | |
118 | cls::rbd::MirrorImage mirror_image; | |
119 | bufferlist::iterator iter = m_out_bl.begin(); | |
120 | r = librbd::cls_client::mirror_image_get_finish(&iter, &mirror_image); | |
121 | if (r == 0) { | |
122 | m_parent_global_image_id = mirror_image.global_image_id; | |
123 | dout(20) << ": parent_global_image_id=" << m_parent_global_image_id | |
124 | << dendl; | |
125 | } | |
126 | } | |
127 | ||
128 | if (r == -ENOENT) { | |
129 | dout(10) << ": parent image " << m_remote_parent_spec.image_id << " not mirrored" | |
130 | << dendl; | |
131 | finish(r); | |
132 | return; | |
133 | } else if (r < 0) { | |
134 | derr << ": failed to retrieve global image id for parent image " | |
135 | << m_remote_parent_spec.image_id << ": " << cpp_strerror(r) << dendl; | |
136 | finish(r); | |
137 | return; | |
138 | } | |
139 | ||
140 | get_local_parent_image_id(); | |
141 | } | |
142 | ||
143 | template <typename I> | |
144 | void CreateImageRequest<I>::get_local_parent_image_id() { | |
145 | dout(20) << dendl; | |
146 | ||
147 | librados::ObjectReadOperation op; | |
148 | librbd::cls_client::mirror_image_get_image_id_start( | |
149 | &op, m_parent_global_image_id); | |
150 | ||
151 | librados::AioCompletion *aio_comp = create_rados_callback< | |
152 | CreateImageRequest<I>, | |
153 | &CreateImageRequest<I>::handle_get_local_parent_image_id>(this); | |
154 | m_out_bl.clear(); | |
155 | int r = m_local_parent_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, | |
156 | &m_out_bl); | |
157 | assert(r == 0); | |
158 | aio_comp->release(); | |
159 | } | |
160 | ||
161 | template <typename I> | |
162 | void CreateImageRequest<I>::handle_get_local_parent_image_id(int r) { | |
163 | dout(20) << ": r=" << r << dendl; | |
164 | ||
165 | if (r == 0) { | |
166 | bufferlist::iterator iter = m_out_bl.begin(); | |
167 | r = librbd::cls_client::mirror_image_get_image_id_finish( | |
168 | &iter, &m_local_parent_spec.image_id); | |
169 | } | |
170 | ||
171 | if (r == -ENOENT) { | |
172 | dout(10) << ": parent image " << m_parent_global_image_id << " not " | |
173 | << "registered locally" << dendl; | |
174 | finish(r); | |
175 | return; | |
176 | } else if (r < 0) { | |
177 | derr << ": failed to retrieve local image id for parent image " | |
178 | << m_parent_global_image_id << ": " << cpp_strerror(r) << dendl; | |
179 | finish(r); | |
180 | return; | |
181 | } | |
182 | ||
183 | open_remote_parent_image(); | |
184 | } | |
185 | ||
186 | template <typename I> | |
187 | void CreateImageRequest<I>::open_remote_parent_image() { | |
188 | dout(20) << dendl; | |
189 | ||
190 | Context *ctx = create_context_callback< | |
191 | CreateImageRequest<I>, | |
192 | &CreateImageRequest<I>::handle_open_remote_parent_image>(this); | |
193 | OpenImageRequest<I> *request = OpenImageRequest<I>::create( | |
194 | m_remote_parent_io_ctx, &m_remote_parent_image_ctx, | |
195 | m_remote_parent_spec.image_id, true, ctx); | |
196 | request->send(); | |
197 | } | |
198 | ||
199 | template <typename I> | |
200 | void CreateImageRequest<I>::handle_open_remote_parent_image(int r) { | |
201 | dout(20) << ": r=" << r << dendl; | |
202 | if (r < 0) { | |
203 | derr << ": failed to open remote parent image " << m_parent_pool_name << "/" | |
204 | << m_remote_parent_spec.image_id << dendl; | |
205 | finish(r); | |
206 | return; | |
207 | } | |
208 | ||
209 | open_local_parent_image(); | |
210 | } | |
211 | ||
212 | template <typename I> | |
213 | void CreateImageRequest<I>::open_local_parent_image() { | |
214 | dout(20) << dendl; | |
215 | ||
216 | Context *ctx = create_context_callback< | |
217 | CreateImageRequest<I>, | |
218 | &CreateImageRequest<I>::handle_open_local_parent_image>(this); | |
219 | OpenImageRequest<I> *request = OpenImageRequest<I>::create( | |
220 | m_local_parent_io_ctx, &m_local_parent_image_ctx, | |
221 | m_local_parent_spec.image_id, true, ctx); | |
222 | request->send(); | |
223 | } | |
224 | ||
225 | template <typename I> | |
226 | void CreateImageRequest<I>::handle_open_local_parent_image(int r) { | |
227 | dout(20) << ": r=" << r << dendl; | |
228 | if (r < 0) { | |
229 | derr << ": failed to open local parent image " << m_parent_pool_name << "/" | |
230 | << m_local_parent_spec.image_id << dendl; | |
231 | m_ret_val = r; | |
232 | close_remote_parent_image(); | |
233 | return; | |
234 | } | |
235 | ||
236 | set_local_parent_snap(); | |
237 | } | |
238 | ||
239 | template <typename I> | |
240 | void CreateImageRequest<I>::set_local_parent_snap() { | |
241 | dout(20) << dendl; | |
242 | ||
243 | { | |
244 | RWLock::RLocker remote_snap_locker(m_remote_parent_image_ctx->snap_lock); | |
245 | auto it = m_remote_parent_image_ctx->snap_info.find( | |
246 | m_remote_parent_spec.snap_id); | |
247 | if (it != m_remote_parent_image_ctx->snap_info.end()) { | |
248 | m_parent_snap_name = it->second.name; | |
249 | } | |
250 | } | |
251 | ||
252 | if (m_parent_snap_name.empty()) { | |
253 | m_ret_val = -ENOENT; | |
254 | close_local_parent_image(); | |
255 | return; | |
256 | } | |
257 | dout(20) << ": parent_snap_name=" << m_parent_snap_name << dendl; | |
258 | ||
259 | Context *ctx = create_context_callback< | |
260 | CreateImageRequest<I>, | |
261 | &CreateImageRequest<I>::handle_set_local_parent_snap>(this); | |
262 | m_local_parent_image_ctx->state->snap_set(cls::rbd::UserSnapshotNamespace(), | |
263 | m_parent_snap_name, | |
264 | ctx); | |
265 | } | |
266 | ||
267 | template <typename I> | |
268 | void CreateImageRequest<I>::handle_set_local_parent_snap(int r) { | |
269 | dout(20) << ": r=" << r << dendl; | |
270 | if (r < 0) { | |
271 | derr << ": failed to set parent snapshot " << m_parent_snap_name | |
272 | << ": " << cpp_strerror(r) << dendl; | |
273 | m_ret_val = r; | |
274 | close_local_parent_image(); | |
275 | return; | |
276 | } | |
277 | ||
278 | clone_image(); | |
279 | } | |
280 | ||
281 | template <typename I> | |
282 | void CreateImageRequest<I>::clone_image() { | |
283 | dout(20) << dendl; | |
284 | ||
285 | librbd::ImageOptions opts; | |
286 | opts.set(RBD_IMAGE_OPTION_FEATURES, m_remote_image_ctx->features); | |
287 | opts.set(RBD_IMAGE_OPTION_ORDER, m_remote_image_ctx->order); | |
288 | opts.set(RBD_IMAGE_OPTION_STRIPE_UNIT, m_remote_image_ctx->stripe_unit); | |
289 | opts.set(RBD_IMAGE_OPTION_STRIPE_COUNT, m_remote_image_ctx->stripe_count); | |
290 | ||
7c673cae FG |
291 | using klass = CreateImageRequest<I>; |
292 | Context *ctx = create_context_callback<klass, &klass::handle_clone_image>(this); | |
293 | ||
294 | librbd::image::CloneRequest<I> *req = librbd::image::CloneRequest<I>::create( | |
295 | m_local_parent_image_ctx, m_local_io_ctx, m_local_image_name, | |
d2e6a577 | 296 | m_local_image_id, opts, m_global_image_id, m_remote_mirror_uuid, |
7c673cae FG |
297 | m_remote_image_ctx->op_work_queue, ctx); |
298 | req->send(); | |
299 | } | |
300 | ||
301 | template <typename I> | |
302 | void CreateImageRequest<I>::handle_clone_image(int r) { | |
303 | dout(20) << ": r=" << r << dendl; | |
304 | if (r < 0) { | |
305 | derr << ": failed to clone image " << m_parent_pool_name << "/" | |
306 | << m_local_parent_image_ctx->name << " to " | |
307 | << m_local_image_name << dendl; | |
308 | m_ret_val = r; | |
309 | } | |
310 | ||
311 | close_local_parent_image(); | |
312 | } | |
313 | ||
314 | template <typename I> | |
315 | void CreateImageRequest<I>::close_local_parent_image() { | |
316 | dout(20) << dendl; | |
317 | Context *ctx = create_context_callback< | |
318 | CreateImageRequest<I>, | |
319 | &CreateImageRequest<I>::handle_close_local_parent_image>(this); | |
320 | CloseImageRequest<I> *request = CloseImageRequest<I>::create( | |
321 | &m_local_parent_image_ctx, ctx); | |
322 | request->send(); | |
323 | } | |
324 | ||
325 | template <typename I> | |
326 | void CreateImageRequest<I>::handle_close_local_parent_image(int r) { | |
327 | dout(20) << ": r=" << r << dendl; | |
328 | if (r < 0) { | |
329 | derr << ": error encountered closing local parent image: " | |
330 | << cpp_strerror(r) << dendl; | |
331 | } | |
332 | ||
333 | close_remote_parent_image(); | |
334 | } | |
335 | ||
336 | template <typename I> | |
337 | void CreateImageRequest<I>::close_remote_parent_image() { | |
338 | dout(20) << dendl; | |
339 | Context *ctx = create_context_callback< | |
340 | CreateImageRequest<I>, | |
341 | &CreateImageRequest<I>::handle_close_remote_parent_image>(this); | |
342 | CloseImageRequest<I> *request = CloseImageRequest<I>::create( | |
343 | &m_remote_parent_image_ctx, ctx); | |
344 | request->send(); | |
345 | } | |
346 | ||
347 | template <typename I> | |
348 | void CreateImageRequest<I>::handle_close_remote_parent_image(int r) { | |
349 | dout(20) << ": r=" << r << dendl; | |
350 | if (r < 0) { | |
351 | derr << ": error encountered closing remote parent image: " | |
352 | << cpp_strerror(r) << dendl; | |
353 | } | |
354 | ||
355 | finish(m_ret_val); | |
356 | } | |
357 | ||
358 | template <typename I> | |
359 | void CreateImageRequest<I>::error(int r) { | |
360 | dout(20) << ": r=" << r << dendl; | |
361 | ||
362 | m_work_queue->queue(create_context_callback< | |
363 | CreateImageRequest<I>, &CreateImageRequest<I>::finish>(this), r); | |
364 | } | |
365 | ||
366 | template <typename I> | |
367 | void CreateImageRequest<I>::finish(int r) { | |
368 | dout(20) << ": r=" << r << dendl; | |
369 | m_on_finish->complete(r); | |
370 | delete this; | |
371 | } | |
372 | ||
373 | template <typename I> | |
374 | int CreateImageRequest<I>::validate_parent() { | |
375 | RWLock::RLocker owner_locker(m_remote_image_ctx->owner_lock); | |
376 | RWLock::RLocker snap_locker(m_remote_image_ctx->snap_lock); | |
377 | ||
378 | m_remote_parent_spec = m_remote_image_ctx->parent_md.spec; | |
379 | ||
380 | // scan all remote snapshots for a linked parent | |
381 | for (auto &snap_info_pair : m_remote_image_ctx->snap_info) { | |
382 | auto &parent_spec = snap_info_pair.second.parent.spec; | |
383 | if (parent_spec.pool_id == -1) { | |
384 | continue; | |
385 | } else if (m_remote_parent_spec.pool_id == -1) { | |
386 | m_remote_parent_spec = parent_spec; | |
387 | continue; | |
388 | } | |
389 | ||
390 | if (m_remote_parent_spec != parent_spec) { | |
391 | derr << ": remote image parent spec mismatch" << dendl; | |
392 | return -EINVAL; | |
393 | } | |
394 | } | |
395 | ||
396 | if (m_remote_parent_spec.pool_id == -1) { | |
397 | return 0; | |
398 | } | |
399 | ||
400 | // map remote parent pool to local parent pool | |
401 | librados::Rados remote_rados(m_remote_image_ctx->md_ctx); | |
402 | int r = remote_rados.ioctx_create2(m_remote_parent_spec.pool_id, | |
403 | m_remote_parent_io_ctx); | |
404 | if (r < 0) { | |
405 | derr << ": failed to open remote parent pool " << m_remote_parent_spec.pool_id | |
406 | << ": " << cpp_strerror(r) << dendl; | |
407 | return r; | |
408 | } | |
409 | ||
410 | m_parent_pool_name = m_remote_parent_io_ctx.get_pool_name(); | |
411 | ||
412 | librados::Rados local_rados(m_local_io_ctx); | |
413 | r = local_rados.ioctx_create(m_parent_pool_name.c_str(), | |
414 | m_local_parent_io_ctx); | |
415 | if (r < 0) { | |
416 | derr << ": failed to open local parent pool " << m_parent_pool_name << ": " | |
417 | << cpp_strerror(r) << dendl; | |
418 | return r; | |
419 | } | |
420 | ||
421 | return 0; | |
422 | } | |
423 | ||
424 | } // namespace image_replayer | |
425 | } // namespace mirror | |
426 | } // namespace rbd | |
427 | ||
428 | template class rbd::mirror::image_replayer::CreateImageRequest<librbd::ImageCtx>; |