]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/image/RemoveRequest.cc
update sources to 12.2.8
[ceph.git] / ceph / src / librbd / image / RemoveRequest.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 "common/dout.h"
5 #include "common/errno.h"
6 #include "librbd/internal.h"
7 #include "librbd/ImageState.h"
8 #include "librbd/Journal.h"
9 #include "librbd/ObjectMap.h"
10 #include "librbd/ExclusiveLock.h"
11 #include "librbd/MirroringWatcher.h"
12 #include "librbd/journal/DisabledPolicy.h"
13 #include "librbd/journal/RemoveRequest.h"
14 #include "librbd/image/RemoveRequest.h"
15 #include "librbd/operation/TrimRequest.h"
16 #include "librbd/mirror/DisableRequest.h"
17
18 #define dout_subsys ceph_subsys_rbd
19 #undef dout_prefix
20 #define dout_prefix *_dout << "librbd::image::RemoveRequest: " << this << " " \
21 << __func__ << ": "
22
23 namespace librbd {
24 namespace image {
25
26 using librados::IoCtx;
27 using util::create_context_callback;
28 using util::create_async_context_callback;
29 using util::create_rados_callback;
30
31 template<typename I>
32 RemoveRequest<I>::RemoveRequest(IoCtx &ioctx, const std::string &image_name,
33 const std::string &image_id, bool force,
34 bool from_trash_remove,
35 ProgressContext &prog_ctx,
36 ContextWQ *op_work_queue, Context *on_finish)
37 : m_ioctx(ioctx), m_image_name(image_name), m_image_id(image_id),
38 m_force(force), m_from_trash_remove(from_trash_remove),
39 m_prog_ctx(prog_ctx), m_op_work_queue(op_work_queue),
40 m_on_finish(on_finish) {
41 m_cct = reinterpret_cast<CephContext *>(m_ioctx.cct());
42
43 m_image_ctx = I::create((m_image_id.empty() ? m_image_name : std::string()),
44 m_image_id, nullptr, m_ioctx, false);
45 }
46
47 template<typename I>
48 void RemoveRequest<I>::send() {
49 ldout(m_cct, 20) << dendl;
50
51 open_image();
52 }
53
54 template<typename I>
55 void RemoveRequest<I>::open_image() {
56 ldout(m_cct, 20) << dendl;
57
58 using klass = RemoveRequest<I>;
59 Context *ctx = create_context_callback<klass, &klass::handle_open_image>(
60 this);
61
62 m_image_ctx->state->open(true, ctx);
63 }
64
65 template<typename I>
66 void RemoveRequest<I>::handle_open_image(int r) {
67 ldout(m_cct, 20) << "r=" << r << dendl;
68
69 if (r < 0) {
70 m_image_ctx->destroy();
71 m_image_ctx = nullptr;
72
73 if (r != -ENOENT) {
74 lderr(m_cct) << "error opening image: " << cpp_strerror(r) << dendl;
75 finish(r);
76 return;
77 }
78
79 remove_image();
80 return;
81 }
82
83 m_image_id = m_image_ctx->id;
84 m_image_name = m_image_ctx->name;
85 m_header_oid = m_image_ctx->header_oid;
86 m_old_format = m_image_ctx->old_format;
87 m_unknown_format = false;
88
89 check_exclusive_lock();
90 }
91
92 template<typename I>
93 void RemoveRequest<I>::check_exclusive_lock() {
94 ldout(m_cct, 20) << dendl;
95
96 if (m_image_ctx->exclusive_lock == nullptr) {
97 validate_image_removal();
98 } else {
99 acquire_exclusive_lock();
100 }
101 }
102
103 template<typename I>
104 void RemoveRequest<I>::acquire_exclusive_lock() {
105 ldout(m_cct, 20) << dendl;
106
107 // do not attempt to open the journal when removing the image in case
108 // it's corrupt
109 if (m_image_ctx->test_features(RBD_FEATURE_JOURNALING)) {
110 RWLock::WLocker snap_locker(m_image_ctx->snap_lock);
111 m_image_ctx->set_journal_policy(new journal::DisabledPolicy());
112 }
113
114 using klass = RemoveRequest<I>;
115 if (m_force) {
116 Context *ctx = create_context_callback<
117 klass, &klass::handle_exclusive_lock_force>(this);
118 m_exclusive_lock = m_image_ctx->exclusive_lock;
119 m_exclusive_lock->shut_down(ctx);
120 } else {
121 Context *ctx = create_context_callback<
122 klass, &klass::handle_exclusive_lock>(this);
123 RWLock::WLocker owner_lock(m_image_ctx->owner_lock);
124 m_image_ctx->exclusive_lock->try_acquire_lock(ctx);
125 }
126 }
127
128 template<typename I>
129 void RemoveRequest<I>::handle_exclusive_lock_force(int r) {
130 ldout(m_cct, 20) << "r=" << r << dendl;
131
132 delete m_exclusive_lock;
133 m_exclusive_lock = nullptr;
134
135 if (r < 0) {
136 lderr(m_cct) << "error shutting down exclusive lock: "
137 << cpp_strerror(r) << dendl;
138 send_close_image(r);
139 return;
140 }
141
142 assert(m_image_ctx->exclusive_lock == nullptr);
143 validate_image_removal();
144 }
145
146 template<typename I>
147 void RemoveRequest<I>::handle_exclusive_lock(int r) {
148 ldout(m_cct, 20) << "r=" << r << dendl;
149
150 if (r < 0 || !m_image_ctx->exclusive_lock->is_lock_owner()) {
151 lderr(m_cct) << "cannot obtain exclusive lock - not removing" << dendl;
152 send_close_image(-EBUSY);
153 return;
154 }
155
156 validate_image_removal();
157 }
158
159 template<typename I>
160 void RemoveRequest<I>::validate_image_removal() {
161 ldout(m_cct, 20) << dendl;
162
163 check_image_snaps();
164 }
165
166 template<typename I>
167 void RemoveRequest<I>::check_image_snaps() {
168 ldout(m_cct, 20) << dendl;
169
170 if (m_image_ctx->snaps.size()) {
171 lderr(m_cct) << "image has snapshots - not removing" << dendl;
172 send_close_image(-ENOTEMPTY);
173 return;
174 }
175
176 list_image_watchers();
177 }
178
179 template<typename I>
180 void RemoveRequest<I>::list_image_watchers() {
181 ldout(m_cct, 20) << dendl;
182
183 librados::ObjectReadOperation op;
184 op.list_watchers(&m_watchers, &m_ret_val);
185
186 using klass = RemoveRequest<I>;
187 librados::AioCompletion *rados_completion =
188 create_rados_callback<klass, &klass::handle_list_image_watchers>(this);
189
190 int r = m_image_ctx->md_ctx.aio_operate(m_header_oid, rados_completion,
191 &op, &m_out_bl);
192 assert(r == 0);
193 rados_completion->release();
194 }
195
196 template<typename I>
197 void RemoveRequest<I>::handle_list_image_watchers(int r) {
198 ldout(m_cct, 20) << "r=" << r << dendl;
199
200 if (r == 0 && m_ret_val < 0) {
201 r = m_ret_val;
202 }
203 if (r < 0) {
204 lderr(m_cct) << "error listing image watchers: " << cpp_strerror(r)
205 << dendl;
206 send_close_image(r);
207 return;
208 }
209
210 get_mirror_image();
211 }
212
213 template<typename I>
214 void RemoveRequest<I>::get_mirror_image() {
215 ldout(m_cct, 20) << dendl;
216 if ((m_watchers.empty()) ||
217 ((m_image_ctx->features & RBD_FEATURE_JOURNALING) == 0)) {
218 check_image_watchers();
219 return;
220 }
221
222 librados::ObjectReadOperation op;
223 cls_client::mirror_image_get_start(&op, m_image_id);
224
225 using klass = RemoveRequest<I>;
226 librados::AioCompletion *comp =
227 create_rados_callback<klass, &klass::handle_get_mirror_image>(this);
228 m_out_bl.clear();
229 int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
230 assert(r == 0);
231 comp->release();
232 }
233
234 template<typename I>
235 void RemoveRequest<I>::handle_get_mirror_image(int r) {
236 ldout(m_cct, 20) << "r=" << r << dendl;
237
238 if (r == -ENOENT || r == -EOPNOTSUPP) {
239 check_image_watchers();
240 return;
241 } else if (r < 0) {
242 ldout(m_cct, 5) << "error retrieving mirror image: " << cpp_strerror(r)
243 << dendl;
244 }
245
246 list_mirror_watchers();
247 }
248
249 template<typename I>
250 void RemoveRequest<I>::list_mirror_watchers() {
251 ldout(m_cct, 20) << dendl;
252
253 librados::ObjectReadOperation op;
254 op.list_watchers(&m_mirror_watchers, &m_ret_val);
255
256 using klass = RemoveRequest<I>;
257 librados::AioCompletion *rados_completion =
258 create_rados_callback<klass, &klass::handle_list_mirror_watchers>(this);
259 m_out_bl.clear();
260 int r = m_image_ctx->md_ctx.aio_operate(RBD_MIRRORING, rados_completion,
261 &op, &m_out_bl);
262 assert(r == 0);
263 rados_completion->release();
264 }
265
266 template<typename I>
267 void RemoveRequest<I>::handle_list_mirror_watchers(int r) {
268 ldout(m_cct, 20) << "r=" << r << dendl;
269
270 if (r == 0 && m_ret_val < 0) {
271 r = m_ret_val;
272 }
273 if (r < 0 && r != -ENOENT) {
274 ldout(m_cct, 5) << "error listing mirror watchers: " << cpp_strerror(r)
275 << dendl;
276 }
277
278 for (auto &watcher : m_mirror_watchers) {
279 m_watchers.remove_if([watcher] (obj_watch_t &w) {
280 return (strncmp(w.addr, watcher.addr, sizeof(w.addr)) == 0);
281 });
282 }
283
284 check_image_watchers();
285 }
286
287 template<typename I>
288 void RemoveRequest<I>::check_image_watchers() {
289 if (m_watchers.size() > 1) {
290 lderr(m_cct) << "image has watchers - not removing" << dendl;
291 send_close_image(-EBUSY);
292 return;
293 }
294
295 check_group();
296 }
297
298 template<typename I>
299 void RemoveRequest<I>::check_group() {
300 ldout(m_cct, 20) << dendl;
301
302 librados::ObjectReadOperation op;
303 librbd::cls_client::image_get_group_start(&op);
304
305 using klass = RemoveRequest<I>;
306 librados::AioCompletion *rados_completion = create_rados_callback<
307 klass, &klass::handle_check_group>(this);
308 m_out_bl.clear();
309 int r = m_image_ctx->md_ctx.aio_operate(m_header_oid, rados_completion, &op,
310 &m_out_bl);
311 assert(r == 0);
312 rados_completion->release();
313 }
314
315 template<typename I>
316 void RemoveRequest<I>::handle_check_group(int r) {
317 ldout(m_cct, 20) << "r=" << r << dendl;
318
319 cls::rbd::GroupSpec s;
320 if (r == 0) {
321 bufferlist::iterator it = m_out_bl.begin();
322 r = librbd::cls_client::image_get_group_finish(&it, &s);
323 }
324 if (r < 0 && r != -EOPNOTSUPP) {
325 lderr(m_cct) << "error fetching group for image: "
326 << cpp_strerror(r) << dendl;
327 send_close_image(r);
328 return;
329 }
330
331 if (s.is_valid()) {
332 lderr(m_cct) << "image is in a group - not removing" << dendl;
333 send_close_image(-EMLINK);
334 return;
335 }
336
337 trim_image();
338 }
339
340 template<typename I>
341 void RemoveRequest<I>::trim_image() {
342 ldout(m_cct, 20) << dendl;
343
344 using klass = RemoveRequest<I>;
345 Context *ctx = create_async_context_callback(
346 *m_image_ctx, create_context_callback<
347 klass, &klass::handle_trim_image>(this));
348
349 RWLock::RLocker owner_lock(m_image_ctx->owner_lock);
350 auto req = librbd::operation::TrimRequest<I>::create(
351 *m_image_ctx, ctx, m_image_ctx->size, 0, m_prog_ctx);
352 req->send();
353 }
354
355 template<typename I>
356 void RemoveRequest<I>::handle_trim_image(int r) {
357 ldout(m_cct, 20) << "r=" << r << dendl;
358
359 if (r < 0) {
360 lderr(m_cct) << "warning: failed to remove some object(s): "
361 << cpp_strerror(r) << dendl;
362 }
363
364 if (m_old_format) {
365 send_close_image(r);
366 return;
367 }
368
369 remove_child();
370 }
371
372 template<typename I>
373 void RemoveRequest<I>::remove_child() {
374 ldout(m_cct, 20) << dendl;
375
376 m_image_ctx->parent_lock.get_read();
377 ParentInfo parent_info = m_image_ctx->parent_md;
378 m_image_ctx->parent_lock.put_read();
379
380 librados::ObjectWriteOperation op;
381 librbd::cls_client::remove_child(&op, parent_info.spec, m_image_id);
382
383 using klass = RemoveRequest<I>;
384 librados::AioCompletion *rados_completion =
385 create_rados_callback<klass, &klass::handle_remove_child>(this);
386 int r = m_image_ctx->md_ctx.aio_operate(RBD_CHILDREN, rados_completion, &op);
387 assert(r == 0);
388 rados_completion->release();
389 }
390
391 template<typename I>
392 void RemoveRequest<I>::handle_remove_child(int r) {
393 ldout(m_cct, 20) << "r=" << r << dendl;
394
395 if (r == -ENOENT) {
396 r = 0;
397 } else if (r < 0) {
398 lderr(m_cct) << "error removing child from children list: "
399 << cpp_strerror(r) << dendl;
400 send_close_image(r);
401 return;
402 }
403
404
405 send_disable_mirror();
406 }
407
408 template<typename I>
409 void RemoveRequest<I>::send_disable_mirror() {
410 ldout(m_cct, 20) << dendl;
411
412 using klass = RemoveRequest<I>;
413 Context *ctx = create_context_callback<
414 klass, &klass::handle_disable_mirror>(this);
415
416 mirror::DisableRequest<I> *req =
417 mirror::DisableRequest<I>::create(m_image_ctx, m_force, !m_force, ctx);
418 req->send();
419 }
420
421 template<typename I>
422 void RemoveRequest<I>::handle_disable_mirror(int r) {
423 ldout(m_cct, 20) << "r=" << r << dendl;
424
425 if (r == -EOPNOTSUPP) {
426 r = 0;
427 } else if (r < 0) {
428 lderr(m_cct) << "error disabling image mirroring: "
429 << cpp_strerror(r) << dendl;
430 }
431
432 send_close_image(r);
433 }
434
435 template<typename I>
436 void RemoveRequest<I>::send_close_image(int r) {
437 ldout(m_cct, 20) << dendl;
438
439 m_ret_val = r;
440 using klass = RemoveRequest<I>;
441 Context *ctx = create_context_callback<
442 klass, &klass::handle_send_close_image>(this);
443
444 m_image_ctx->state->close(ctx);
445 }
446
447 template<typename I>
448 void RemoveRequest<I>::handle_send_close_image(int r) {
449 ldout(m_cct, 20) << "r=" << r << dendl;
450
451 if (r < 0) {
452 lderr(m_cct) << "error encountered while closing image: "
453 << cpp_strerror(r) << dendl;
454 }
455
456 m_image_ctx->destroy();
457 m_image_ctx = nullptr;
458 if (m_ret_val < 0) {
459 r = m_ret_val;
460 finish(r);
461 return;
462 }
463
464 remove_header();
465 }
466
467 template<typename I>
468 void RemoveRequest<I>::remove_header() {
469 ldout(m_cct, 20) << dendl;
470
471 using klass = RemoveRequest<I>;
472 librados::AioCompletion *rados_completion =
473 create_rados_callback<klass, &klass::handle_remove_header>(this);
474 int r = m_ioctx.aio_remove(m_header_oid, rados_completion);
475 assert(r == 0);
476 rados_completion->release();
477 }
478
479 template<typename I>
480 void RemoveRequest<I>::handle_remove_header(int r) {
481 ldout(m_cct, 20) << "r=" << r << dendl;
482
483 if (r < 0 && r != -ENOENT) {
484 lderr(m_cct) << "error removing header: " << cpp_strerror(r) << dendl;
485 m_ret_val = r;
486 }
487
488 remove_image();
489 }
490
491 template<typename I>
492 void RemoveRequest<I>::remove_header_v2() {
493 ldout(m_cct, 20) << dendl;
494
495 if (m_header_oid.empty()) {
496 m_header_oid = util::header_name(m_image_id);
497 }
498
499 using klass = RemoveRequest<I>;
500 librados::AioCompletion *rados_completion =
501 create_rados_callback<klass, &klass::handle_remove_header_v2>(this);
502 int r = m_ioctx.aio_remove(m_header_oid, rados_completion);
503 assert(r == 0);
504 rados_completion->release();
505 }
506
507 template<typename I>
508 void RemoveRequest<I>::handle_remove_header_v2(int r) {
509 ldout(m_cct, 20) << "r=" << r << dendl;
510
511 if (r < 0 && r != -ENOENT) {
512 lderr(m_cct) << "error removing header: " << cpp_strerror(r) << dendl;
513 finish(r);
514 return;
515 }
516
517 send_journal_remove();
518 }
519
520 template<typename I>
521 void RemoveRequest<I>::send_journal_remove() {
522 ldout(m_cct, 20) << dendl;
523
524 using klass = RemoveRequest<I>;
525 Context *ctx = create_context_callback<
526 klass, &klass::handle_journal_remove>(this);
527
528 journal::RemoveRequest<I> *req = journal::RemoveRequest<I>::create(
529 m_ioctx, m_image_id, Journal<>::IMAGE_CLIENT_ID, m_op_work_queue, ctx);
530 req->send();
531 }
532
533 template<typename I>
534 void RemoveRequest<I>::handle_journal_remove(int r) {
535 ldout(m_cct, 20) << "r=" << r << dendl;
536
537 if (r < 0 && r != -ENOENT) {
538 lderr(m_cct) << "failed to remove image journal: " << cpp_strerror(r)
539 << dendl;
540 finish(r);
541 return;
542 } else {
543 r = 0;
544 }
545
546 send_object_map_remove();
547 }
548
549 template<typename I>
550 void RemoveRequest<I>::send_object_map_remove() {
551 ldout(m_cct, 20) << dendl;
552
553 using klass = RemoveRequest<I>;
554 librados::AioCompletion *rados_completion =
555 create_rados_callback<klass, &klass::handle_object_map_remove>(this);
556
557 int r = ObjectMap<>::aio_remove(m_ioctx,
558 m_image_id,
559 rados_completion);
560 assert(r == 0);
561 rados_completion->release();
562 }
563
564 template<typename I>
565 void RemoveRequest<I>::handle_object_map_remove(int r) {
566 ldout(m_cct, 20) << "r=" << r << dendl;
567
568 if (r < 0 && r != -ENOENT) {
569 lderr(m_cct) << "failed to remove image journal: " << cpp_strerror(r)
570 << dendl;
571 finish(r);
572 return;
573 } else {
574 r = 0;
575 }
576
577 mirror_image_remove();
578 }
579
580 template<typename I>
581 void RemoveRequest<I>::mirror_image_remove() {
582 ldout(m_cct, 20) << dendl;
583
584 librados::ObjectWriteOperation op;
585 cls_client::mirror_image_remove(&op, m_image_id);
586
587 using klass = RemoveRequest<I>;
588 librados::AioCompletion *rados_completion =
589 create_rados_callback<klass, &klass::handle_mirror_image_remove>(this);
590 int r = m_ioctx.aio_operate(RBD_MIRRORING, rados_completion, &op);
591 assert(r == 0);
592 rados_completion->release();
593 }
594
595 template<typename I>
596 void RemoveRequest<I>::handle_mirror_image_remove(int r) {
597 ldout(m_cct, 20) << "r=" << r << dendl;
598
599 if (r < 0 && r != -ENOENT && r != -EOPNOTSUPP) {
600 lderr(m_cct) << "failed to remove mirror image state: "
601 << cpp_strerror(r) << dendl;
602 finish(r);
603 return;
604 }
605
606 if (m_from_trash_remove) {
607 // both the id object and the directory entry have been removed in
608 // a previous call to trash_move.
609 finish(0);
610 return;
611 }
612
613 remove_id_object();
614 }
615
616 template<typename I>
617 void RemoveRequest<I>::remove_image() {
618 ldout(m_cct, 20) << dendl;
619
620 if (m_old_format || m_unknown_format) {
621 remove_v1_image();
622 } else {
623 remove_v2_image();
624 }
625 }
626
627 template<typename I>
628 void RemoveRequest<I>::remove_v1_image() {
629 ldout(m_cct, 20) << dendl;
630
631 Context *ctx = new FunctionContext([this] (int r) {
632 r = tmap_rm(m_ioctx, m_image_name);
633 handle_remove_v1_image(r);
634 });
635
636 m_op_work_queue->queue(ctx, 0);
637 }
638
639 template<typename I>
640 void RemoveRequest<I>::handle_remove_v1_image(int r) {
641 ldout(m_cct, 20) << "r=" << r << dendl;
642
643 m_old_format = (r == 0);
644 if (r == 0 || (r < 0 && !m_unknown_format)) {
645 if (r < 0 && r != -ENOENT) {
646 lderr(m_cct) << "error removing image from v1 directory: "
647 << cpp_strerror(r) << dendl;
648 }
649
650 m_on_finish->complete(r);
651 delete this;
652 return;
653 }
654
655 if (!m_old_format) {
656 remove_v2_image();
657 }
658 }
659
660 template<typename I>
661 void RemoveRequest<I>::remove_v2_image() {
662 ldout(m_cct, 20) << dendl;
663
664 if (m_image_id.empty()) {
665 dir_get_image_id();
666 return;
667 } else if (m_image_name.empty()) {
668 dir_get_image_name();
669 return;
670 }
671
672 remove_header_v2();
673 return;
674 }
675
676 template<typename I>
677 void RemoveRequest<I>::dir_get_image_id() {
678 ldout(m_cct, 20) << dendl;
679
680 librados::ObjectReadOperation op;
681 librbd::cls_client::dir_get_id_start(&op, m_image_name);
682
683 using klass = RemoveRequest<I>;
684 librados::AioCompletion *rados_completion =
685 create_rados_callback<klass, &klass::handle_dir_get_image_id>(this);
686 m_out_bl.clear();
687 int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op, &m_out_bl);
688 assert(r == 0);
689 rados_completion->release();
690 }
691
692 template<typename I>
693 void RemoveRequest<I>::handle_dir_get_image_id(int r) {
694 ldout(m_cct, 20) << "r=" << r << dendl;
695
696 if (r < 0 && r != -ENOENT) {
697 lderr(m_cct) << "error fetching image id: " << cpp_strerror(r)
698 << dendl;
699 finish(r);
700 return;
701 }
702
703 if (r == 0) {
704 bufferlist::iterator iter = m_out_bl.begin();
705 r = librbd::cls_client::dir_get_id_finish(&iter, &m_image_id);
706 if (r < 0) {
707 finish(r);
708 return;
709 }
710 }
711
712 remove_header_v2();
713 }
714
715 template<typename I>
716 void RemoveRequest<I>::dir_get_image_name() {
717 ldout(m_cct, 20) << dendl;
718
719 librados::ObjectReadOperation op;
720 librbd::cls_client::dir_get_name_start(&op, m_image_id);
721
722 using klass = RemoveRequest<I>;
723 librados::AioCompletion *rados_completion =
724 create_rados_callback<klass, &klass::handle_dir_get_image_name>(this);
725 m_out_bl.clear();
726 int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op, &m_out_bl);
727 assert(r == 0);
728 rados_completion->release();
729 }
730
731 template<typename I>
732 void RemoveRequest<I>::handle_dir_get_image_name(int r) {
733 ldout(m_cct, 20) << "r=" << r << dendl;
734
735 if (r < 0 && r != -ENOENT) {
736 lderr(m_cct) << "error fetching image name: " << cpp_strerror(r)
737 << dendl;
738 finish(r);
739 return;
740 }
741
742 if (r == 0) {
743 bufferlist::iterator iter = m_out_bl.begin();
744 r = librbd::cls_client::dir_get_name_finish(&iter, &m_image_name);
745 if (r < 0) {
746 finish(r);
747 return;
748 }
749 }
750
751 remove_header_v2();
752 }
753
754 template<typename I>
755 void RemoveRequest<I>::remove_id_object() {
756 ldout(m_cct, 20) << dendl;
757
758 using klass = RemoveRequest<I>;
759 librados::AioCompletion *rados_completion =
760 create_rados_callback<klass, &klass::handle_remove_id_object>(this);
761 int r = m_ioctx.aio_remove(util::id_obj_name(m_image_name), rados_completion);
762 assert(r == 0);
763 rados_completion->release();
764 }
765
766 template<typename I>
767 void RemoveRequest<I>::handle_remove_id_object(int r) {
768 ldout(m_cct, 20) << "r=" << r << dendl;
769
770 if (r < 0 && r != -ENOENT) {
771 lderr(m_cct) << "error removing id object: " << cpp_strerror(r)
772 << dendl;
773 finish(r);
774 return;
775 }
776
777 dir_remove_image();
778 }
779
780 template<typename I>
781 void RemoveRequest<I>::dir_remove_image() {
782 ldout(m_cct, 20) << dendl;
783
784 librados::ObjectWriteOperation op;
785 librbd::cls_client::dir_remove_image(&op, m_image_name, m_image_id);
786
787 using klass = RemoveRequest<I>;
788 librados::AioCompletion *rados_completion =
789 create_rados_callback<klass, &klass::handle_dir_remove_image>(this);
790 int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op);
791 assert(r == 0);
792 rados_completion->release();
793 }
794
795 template<typename I>
796 void RemoveRequest<I>::handle_dir_remove_image(int r) {
797 ldout(m_cct, 20) << "r=" << r << dendl;
798
799 if (r < 0 && r != -ENOENT) {
800 lderr(m_cct) << "error removing image from v2 directory: "
801 << cpp_strerror(r) << dendl;
802 }
803
804 finish(r);
805 }
806
807 template<typename I>
808 void RemoveRequest<I>::finish(int r) {
809 ldout(m_cct, 20) << "r=" << r << dendl;
810
811 m_on_finish->complete(r);
812 delete this;
813 }
814
815 } // namespace image
816 } // namespace librbd
817
818 template class librbd::image::RemoveRequest<librbd::ImageCtx>;