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