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