]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/image/CloneRequest.cc
update sources to v12.1.3
[ceph.git] / ceph / src / librbd / image / CloneRequest.cc
CommitLineData
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 "cls/rbd/cls_rbd_client.h"
5#include "cls/rbd/cls_rbd_types.h"
6#include "common/dout.h"
7#include "common/errno.h"
8#include "include/assert.h"
9#include "librbd/ImageState.h"
10#include "librbd/Journal.h"
11#include "librbd/image/CloneRequest.h"
12#include "librbd/image/CreateRequest.h"
13#include "librbd/image/RemoveRequest.h"
14#include "librbd/image/RefreshRequest.h"
15#include "librbd/mirror/EnableRequest.h"
16
17#define dout_subsys ceph_subsys_rbd
18#undef dout_prefix
19#define dout_prefix *_dout << "librbd::image::CloneRequest: "
20
21namespace librbd {
22namespace image {
23
24using util::create_rados_callback;
25using util::create_context_callback;
26using util::create_async_context_callback;
27
28template <typename I>
29CloneRequest<I>::CloneRequest(I *p_imctx, IoCtx &c_ioctx,
30 const std::string &c_name,
31 const std::string &c_id,
32 ImageOptions c_options,
33 const std::string &non_primary_global_image_id,
34 const std::string &primary_mirror_uuid,
35 ContextWQ *op_work_queue, Context *on_finish)
36 : m_p_imctx(p_imctx), m_ioctx(c_ioctx), m_name(c_name), m_id(c_id),
37 m_opts(c_options),
38 m_pspec(m_p_imctx->md_ctx.get_id(), m_p_imctx->id, m_p_imctx->snap_id),
39 m_non_primary_global_image_id(non_primary_global_image_id),
40 m_primary_mirror_uuid(primary_mirror_uuid),
41 m_op_work_queue(op_work_queue), m_on_finish(on_finish),
42 m_use_p_features(true) {
43
44 m_cct = reinterpret_cast<CephContext *>(m_ioctx.cct());
45
46 bool default_format_set;
47 m_opts.is_set(RBD_IMAGE_OPTION_FORMAT, &default_format_set);
48 if (!default_format_set) {
49 m_opts.set(RBD_IMAGE_OPTION_FORMAT, static_cast<uint64_t>(2));
50 }
51
52 ldout(m_cct, 20) << "clone " << &m_p_imctx->md_ctx << " name " << m_p_imctx->name
53 << " snap " << m_p_imctx->snap_name << " to child " << &m_ioctx
54 << " name " << m_name << " opts = " << &m_opts << dendl;
55 return;
56}
57
58template <typename I>
59void CloneRequest<I>::send() {
60 ldout(m_cct, 20) << this << " " << __func__ << dendl;
61 validate_options();
62}
63
64template <typename I>
65void CloneRequest<I>::validate_options() {
66 ldout(m_cct, 20) << this << " " << __func__ << dendl;
67
68 uint64_t format = 0;
69 m_opts.get(RBD_IMAGE_OPTION_FORMAT, &format);
70 if (format < 2) {
71 lderr(m_cct) << "format 2 or later required for clone" << dendl;
72 return complete(-EINVAL);
73 }
74
75 if (m_opts.get(RBD_IMAGE_OPTION_FEATURES, &m_features) == 0) {
76 if (m_features & ~RBD_FEATURES_ALL) {
77 lderr(m_cct) << "librbd does not support requested features" << dendl;
78 return complete(-ENOSYS);
79 }
80 m_use_p_features = false;
81 }
82
83 send_validate_parent();
84}
85
86template <typename I>
87void CloneRequest<I>::send_validate_parent() {
88 ldout(m_cct, 20) << this << " " << __func__ << dendl;
89
90 if (m_p_imctx->snap_id == CEPH_NOSNAP) {
91 lderr(m_cct) << "image to be cloned must be a snapshot" << dendl;
92 return complete(-EINVAL);
93 }
94
95 if (m_p_imctx->old_format) {
96 lderr(m_cct) << "parent image must be in new format" << dendl;
97 return complete(-EINVAL);
98 }
99
100 int r = 0;
101 bool snap_protected;
102 m_p_imctx->snap_lock.get_read();
103 m_p_features = m_p_imctx->features;
104 m_size = m_p_imctx->get_image_size(m_p_imctx->snap_id);
105 r = m_p_imctx->is_snap_protected(m_p_imctx->snap_id, &snap_protected);
106 m_p_imctx->snap_lock.put_read();
107
108 if ((m_p_features & RBD_FEATURE_LAYERING) != RBD_FEATURE_LAYERING) {
109 lderr(m_cct) << "parent image must support layering" << dendl;
110 return complete(-ENOSYS);
111 }
112
113 if (r < 0) {
114 lderr(m_cct) << "unable to locate parent's snapshot" << dendl;
115 return complete(r);
116 }
117
118 if (!snap_protected) {
119 lderr(m_cct) << "parent snapshot must be protected" << dendl;
120 return complete(-EINVAL);
121 }
122
123 if ((m_p_features & RBD_FEATURE_JOURNALING) != 0) {
124 m_force_non_primary = !m_non_primary_global_image_id.empty();
125 using klass = CloneRequest<I>;
126 Context *ctx = create_context_callback<
127 klass, &klass::handle_validate_parent>(this);
128
129 Journal<I>::is_tag_owner(m_p_imctx, &m_is_primary, ctx);
130 return;
131 }
132
133 send_validate_child();
134}
135
136template <typename I>
137void CloneRequest<I>::handle_validate_parent(int r) {
138 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
139
140 if (r < 0) {
141 lderr(m_cct) << "failed to determine tag ownership: " << cpp_strerror(r)
142 << dendl;
143 return complete(r);
144 }
145
146 if ((m_p_features & RBD_FEATURE_JOURNALING) != 0) {
147 if (!m_is_primary && !m_force_non_primary) {
148 lderr(m_cct) << "parent is non-primary mirrored image" << dendl;
149 return complete(-EINVAL);
150 }
151 }
152
153 send_validate_child();
154}
155
156template <typename I>
157void CloneRequest<I>::send_validate_child() {
158 ldout(m_cct, 20) << this << " " << __func__ << dendl;
159
160 using klass = CloneRequest<I>;
161 librados::AioCompletion *comp = create_rados_callback<klass, &klass::handle_validate_child>(this);
162
163 librados::ObjectReadOperation op;
164 op.stat(NULL, NULL, NULL);
165
166 int r = m_ioctx.aio_operate(util::old_header_name(m_name), comp, &op, &m_out_bl);
167 assert(r == 0);
168 comp->release();
169}
170
171template <typename I>
172void CloneRequest<I>::handle_validate_child(int r) {
173 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
174
175 if (r != -ENOENT) {
176 lderr(m_cct) << "rbd image " << m_name << " already exists" << dendl;
177 return complete(r);
178 }
179
180 send_create();
181}
182
183template <typename I>
184void CloneRequest<I>::send_create() {
185 ldout(m_cct, 20) << this << " " << __func__ << dendl;
186
187 if (m_use_p_features) {
188 m_features = m_p_features;
189 }
190
191 uint64_t order = m_p_imctx->order;
192 if (m_opts.get(RBD_IMAGE_OPTION_ORDER, &order) != 0) {
193 m_opts.set(RBD_IMAGE_OPTION_ORDER, order);
194 }
195 if ((m_features & RBD_FEATURE_LAYERING) != RBD_FEATURE_LAYERING) {
196 lderr(m_cct) << "cloning image must support layering" << dendl;
197 return complete(-ENOSYS);
198 }
199 m_opts.set(RBD_IMAGE_OPTION_FEATURES, m_features);
200
201 using klass = CloneRequest<I>;
202 Context *ctx = create_context_callback<klass, &klass::handle_create>(this);
203
204 RWLock::RLocker snap_locker(m_p_imctx->snap_lock);
205 CreateRequest<I> *req = CreateRequest<I>::create(
206 m_ioctx, m_name, m_id, m_size, m_opts, m_non_primary_global_image_id,
207 m_primary_mirror_uuid, true, m_op_work_queue, ctx);
208 req->send();
209}
210
211template <typename I>
212void CloneRequest<I>::handle_create(int r) {
213 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
214
215 if (r < 0) {
216 lderr(m_cct) << "error creating child: " << cpp_strerror(r) << dendl;
217 return complete(r);
218 }
219 send_open();
220}
221
222template <typename I>
223void CloneRequest<I>::send_open() {
224 ldout(m_cct, 20) << this << " " << __func__ << dendl;
225
226 m_imctx = I::create(m_name, "", NULL, m_ioctx, false);
227
228 using klass = CloneRequest<I>;
229 Context *ctx = create_context_callback<klass, &klass::handle_open>(this);
230
231 m_imctx->state->open(true, ctx);
232}
233
234template <typename I>
235void CloneRequest<I>::handle_open(int r) {
236 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
237
238 if (r < 0) {
239 lderr(m_cct) << "Error opening new image: " << cpp_strerror(r) << dendl;
240 m_r_saved = r;
241 return send_remove();
242 }
243
244 send_set_parent();
245}
246
247template <typename I>
248void CloneRequest<I>::send_set_parent() {
249 ldout(m_cct, 20) << this << " " << __func__ << dendl;
250
251 librados::ObjectWriteOperation op;
252 librbd::cls_client::set_parent(&op, m_pspec, m_size);
253
254 using klass = CloneRequest<I>;
255 librados::AioCompletion *comp =
256 create_rados_callback<klass, &klass::handle_set_parent>(this);
257 int r = m_imctx->md_ctx.aio_operate(m_imctx->header_oid,
258 comp, &op);
259 assert(r == 0);
260 comp->release();
261}
262
263template <typename I>
264void CloneRequest<I>::handle_set_parent(int r) {
265 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
266
267 if (r < 0) {
268 lderr(m_cct) << "couldn't set parent: " << cpp_strerror(r) << dendl;
269 m_r_saved = r;
270 return send_close();
271 }
272
273 send_add_child();
274}
275
276template <typename I>
277void CloneRequest<I>::send_add_child() {
278 ldout(m_cct, 20) << this << " " << __func__ << dendl;
279
280 librados::ObjectWriteOperation op;
281 cls_client::add_child(&op, m_pspec, m_id);
282
283 using klass = CloneRequest<I>;
284 librados::AioCompletion *comp =
285 create_rados_callback<klass, &klass::handle_add_child>(this);
286 int r = m_ioctx.aio_operate(RBD_CHILDREN, comp, &op);
287 assert(r == 0);
288 comp->release();
289}
290
291template <typename I>
292void CloneRequest<I>::handle_add_child(int r) {
293 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
294
295 if (r < 0) {
296 lderr(m_cct) << "couldn't add child: " << cpp_strerror(r) << dendl;
297 m_r_saved = r;
298 return send_close();
299 }
300
301 send_refresh();
302}
303
304template <typename I>
305void CloneRequest<I>::send_refresh() {
306 ldout(m_cct, 20) << this << " " << __func__ << dendl;
307
308 using klass = CloneRequest<I>;
309 RefreshRequest<I> *req = RefreshRequest<I>::create(
310 *m_imctx, false, false,
311 create_context_callback<klass, &klass::handle_refresh>(this));
312 req->send();
313}
314
315template <typename I>
316void CloneRequest<I>::handle_refresh(int r) {
317 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
318
d2e6a577 319 bool snap_protected = false;
7c673cae
FG
320 if (r == 0) {
321 m_p_imctx->snap_lock.get_read();
322 r = m_p_imctx->is_snap_protected(m_p_imctx->snap_id, &snap_protected);
323 m_p_imctx->snap_lock.put_read();
324 }
325
326 if (r < 0 || !snap_protected) {
327 m_r_saved = -EINVAL;
328 return send_close();
329 }
330
331 send_metadata_list();
332}
333
334template <typename I>
335void CloneRequest<I>::send_metadata_list() {
336 ldout(m_cct, 20) << this << " " << __func__ << dendl;
337
338 librados::ObjectReadOperation op;
339 cls_client::metadata_list_start(&op, "", 0);
340
341 using klass = CloneRequest<I>;
342 librados::AioCompletion *comp =
343 create_rados_callback<klass, &klass::handle_metadata_list>(this);
344 m_out_bl.clear();
345 m_p_imctx->md_ctx.aio_operate(m_p_imctx->header_oid,
346 comp, &op, &m_out_bl);
347 comp->release();
348}
349
350template <typename I>
351void CloneRequest<I>::handle_metadata_list(int r) {
352 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
353
354 if (r == 0) {
355 bufferlist::iterator it = m_out_bl.begin();
356 r = cls_client::metadata_list_finish(&it, &m_pairs);
357 }
358
359 if (r < 0 && r != -EOPNOTSUPP && r != -EIO) {
360 lderr(m_cct) << "couldn't list metadata: " << cpp_strerror(r) << dendl;
361 m_r_saved = r;
362 send_remove_child();
363 } else if (r == 0 && !m_pairs.empty()) {
364 send_metadata_set();
365 } else {
366 get_mirror_mode();
367 }
368}
369
370template <typename I>
371void CloneRequest<I>::send_metadata_set() {
372 ldout(m_cct, 20) << this << " " << __func__ << dendl;
373
374 librados::ObjectWriteOperation op;
375 cls_client::metadata_set(&op, m_pairs);
376
377 using klass = CloneRequest<I>;
378 librados::AioCompletion *comp =
379 create_rados_callback<klass, &klass::handle_metadata_set>(this);
380 int r = m_ioctx.aio_operate(m_imctx->header_oid, comp, &op);
381 assert(r == 0);
382 comp->release();
383}
384
385template <typename I>
386void CloneRequest<I>::handle_metadata_set(int r) {
387 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
388
389 if (r < 0) {
390 lderr(m_cct) << "couldn't set metadata: " << cpp_strerror(r) << dendl;
391 m_r_saved = r;
392 send_remove_child();
393 } else {
394 get_mirror_mode();
395 }
396}
397
398template <typename I>
399void CloneRequest<I>::get_mirror_mode() {
400 ldout(m_cct, 20) << this << " " << __func__ << dendl;
401
402 if (!m_imctx->test_features(RBD_FEATURE_JOURNALING)) {
403 send_close();
404 return;
405 }
406
407 librados::ObjectReadOperation op;
408 cls_client::mirror_mode_get_start(&op);
409
410 using klass = CloneRequest<I>;
411 librados::AioCompletion *comp =
412 create_rados_callback<klass, &klass::handle_get_mirror_mode>(this);
413 m_out_bl.clear();
414 m_imctx->md_ctx.aio_operate(RBD_MIRRORING,
415 comp, &op, &m_out_bl);
416 comp->release();
417}
418
419template <typename I>
420void CloneRequest<I>::handle_get_mirror_mode(int r) {
421 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
422
423 if (r == 0) {
7c673cae
FG
424 bufferlist::iterator it = m_out_bl.begin();
425 r = cls_client::mirror_mode_get_finish(&it, &m_mirror_mode);
426 }
427
428 if (r < 0 && r != -ENOENT) {
c07f9fc5
FG
429 lderr(m_cct) << "failed to retrieve mirror mode: " << cpp_strerror(r)
430 << dendl;
431
7c673cae
FG
432 m_r_saved = r;
433 send_remove_child();
434 } else {
435 if (m_mirror_mode == cls::rbd::MIRROR_MODE_POOL ||
436 !m_non_primary_global_image_id.empty()) {
437 send_enable_mirror();
438 } else {
439 send_close();
440 }
441 }
442}
443
444template <typename I>
445void CloneRequest<I>::send_enable_mirror() {
446 ldout(m_cct, 20) << this << " " << __func__ << dendl;
447
448 using klass = CloneRequest<I>;
449 Context *ctx = create_context_callback<klass, &klass::handle_enable_mirror>(this);
450
451 mirror::EnableRequest<I> *req = mirror::EnableRequest<I>::create(
452 m_imctx->md_ctx, m_id, m_non_primary_global_image_id,
453 m_imctx->op_work_queue, ctx);
454 req->send();
455}
456
457template <typename I>
458void CloneRequest<I>::handle_enable_mirror(int r) {
459 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
460
461 if (r < 0) {
462 lderr(m_cct) << "failed to enable mirroring: " << cpp_strerror(r)
463 << dendl;
464 m_r_saved = r;
465 send_remove_child();
466 } else {
467 send_close();
468 }
469}
470
471template <typename I>
472void CloneRequest<I>::send_close() {
473 ldout(m_cct, 20) << this << " " << __func__ << dendl;
474
475 assert(m_imctx != nullptr);
476
477 using klass = CloneRequest<I>;
478 Context *ctx = create_async_context_callback(
479 *m_imctx, create_context_callback<
480 klass, &klass::handle_close>(this));
481 m_imctx->state->close(ctx);
482}
483
484template <typename I>
485void CloneRequest<I>::handle_close(int r) {
486 ldout(m_cct, 20) << this << " " << __func__ << dendl;
487
488 m_imctx->destroy();
489 m_imctx = nullptr;
490
491 if (r < 0) {
492 lderr(m_cct) << "couldn't close image: " << cpp_strerror(r) << dendl;
493 return complete(r);
494 }
495
496 if (m_r_saved == 0) {
497 complete(0);
498 } else {
499 send_remove();
500 }
501}
502
503template <typename I>
504void CloneRequest<I>::send_remove_child() {
505 ldout(m_cct, 20) << this << " " << __func__ << dendl;
506
507 librados::ObjectWriteOperation op;
508 cls_client::remove_child(&op, m_pspec, m_id);
509
510 using klass = CloneRequest<I>;
511 librados::AioCompletion *comp =
512 create_rados_callback<klass, &klass::handle_remove_child>(this);
513 int r = m_p_imctx->md_ctx.aio_operate(RBD_CHILDREN, comp, &op);
514 assert(r == 0);
515 comp->release();
516}
517
518template <typename I>
519void CloneRequest<I>::handle_remove_child(int r) {
520 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
521
522 if (r < 0) {
523 lderr(m_cct) << "Error removing failed clone from list of children: "
524 << cpp_strerror(r) << dendl;
525 }
526
527 send_close();
528}
529
530template <typename I>
531void CloneRequest<I>::send_remove() {
532 ldout(m_cct, 20) << this << " " << __func__ << dendl;
533
534 using klass = CloneRequest<I>;
535 Context *ctx = create_context_callback<klass, &klass::handle_remove>(this);
536
537 librbd::image::RemoveRequest<> *req = librbd::image::RemoveRequest<>::create(
538 m_ioctx, m_name, m_id, false, false, m_no_op, m_op_work_queue, ctx);
539 req->send();
540}
541
542template <typename I>
543void CloneRequest<I>::handle_remove(int r) {
544 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
545
546 if (r < 0) {
547 lderr(m_cct) << "Error removing failed clone: "
548 << cpp_strerror(r) << dendl;
549 }
550 complete(r);
551}
552
553template <typename I>
554void CloneRequest<I>::complete(int r) {
555 ldout(m_cct, 20) << this << " " << __func__ << " r=" << r << dendl;
556
557 if (r == 0) {
558 ldout(m_cct, 20) << "done." << dendl;
559 }
560
561 m_on_finish->complete(r);
562 delete this;
563}
564
565} //namespace image
566} //namespace librbd
567
568template class librbd::image::CloneRequest<librbd::ImageCtx>;