1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/image/RemoveRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "librbd/internal.h"
8 #include "librbd/ImageState.h"
9 #include "librbd/Journal.h"
10 #include "librbd/ObjectMap.h"
11 #include "librbd/MirroringWatcher.h"
12 #include "librbd/image/DetachChildRequest.h"
13 #include "librbd/image/PreRemoveRequest.h"
14 #include "librbd/journal/RemoveRequest.h"
15 #include "librbd/mirror/DisableRequest.h"
16 #include "librbd/operation/TrimRequest.h"
18 #define dout_subsys ceph_subsys_rbd
20 #define dout_prefix *_dout << "librbd::image::RemoveRequest: " << this << " " \
26 using librados::IoCtx
;
27 using util::create_context_callback
;
28 using util::create_async_context_callback
;
29 using util::create_rados_callback
;
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());
45 RemoveRequest
<I
>::RemoveRequest(IoCtx
&ioctx
, I
*image_ctx
, bool force
,
46 bool from_trash_remove
,
47 ProgressContext
&prog_ctx
,
48 ContextWQ
*op_work_queue
, Context
*on_finish
)
49 : m_ioctx(ioctx
), m_image_name(image_ctx
->name
), m_image_id(image_ctx
->id
),
50 m_image_ctx(image_ctx
), m_force(force
),
51 m_from_trash_remove(from_trash_remove
), m_prog_ctx(prog_ctx
),
52 m_op_work_queue(op_work_queue
), m_on_finish(on_finish
),
53 m_cct(image_ctx
->cct
), m_header_oid(image_ctx
->header_oid
),
54 m_old_format(image_ctx
->old_format
), m_unknown_format(false) {
58 void RemoveRequest
<I
>::send() {
59 ldout(m_cct
, 20) << dendl
;
65 void RemoveRequest
<I
>::open_image() {
66 if (m_image_ctx
!= nullptr) {
71 m_image_ctx
= I::create(m_image_id
.empty() ? m_image_name
: "", m_image_id
,
72 nullptr, m_ioctx
, false);
74 ldout(m_cct
, 20) << dendl
;
76 using klass
= RemoveRequest
<I
>;
77 Context
*ctx
= create_context_callback
<klass
, &klass::handle_open_image
>(
80 m_image_ctx
->state
->open(OPEN_FLAG_SKIP_OPEN_PARENT
, ctx
);
84 void RemoveRequest
<I
>::handle_open_image(int r
) {
85 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
88 m_image_ctx
->destroy();
89 m_image_ctx
= nullptr;
92 lderr(m_cct
) << "error opening image: " << cpp_strerror(r
) << dendl
;
101 m_image_id
= m_image_ctx
->id
;
102 m_image_name
= m_image_ctx
->name
;
103 m_header_oid
= m_image_ctx
->header_oid
;
104 m_old_format
= m_image_ctx
->old_format
;
105 m_unknown_format
= false;
111 void RemoveRequest
<I
>::pre_remove_image() {
112 ldout(m_cct
, 5) << dendl
;
114 auto ctx
= create_context_callback
<
115 RemoveRequest
<I
>, &RemoveRequest
<I
>::handle_pre_remove_image
>(this);
116 auto req
= PreRemoveRequest
<I
>::create(m_image_ctx
, m_force
, ctx
);
121 void RemoveRequest
<I
>::handle_pre_remove_image(int r
) {
122 ldout(m_cct
, 5) << "r=" << r
<< dendl
;
133 void RemoveRequest
<I
>::trim_image() {
134 ldout(m_cct
, 20) << dendl
;
136 using klass
= RemoveRequest
<I
>;
137 Context
*ctx
= create_async_context_callback(
138 *m_image_ctx
, create_context_callback
<
139 klass
, &klass::handle_trim_image
>(this));
141 RWLock::RLocker
owner_lock(m_image_ctx
->owner_lock
);
142 auto req
= librbd::operation::TrimRequest
<I
>::create(
143 *m_image_ctx
, ctx
, m_image_ctx
->size
, 0, m_prog_ctx
);
148 void RemoveRequest
<I
>::handle_trim_image(int r
) {
149 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
152 lderr(m_cct
) << "failed to remove some object(s): "
153 << cpp_strerror(r
) << dendl
;
167 void RemoveRequest
<I
>::detach_child() {
168 ldout(m_cct
, 20) << dendl
;
170 auto ctx
= create_context_callback
<
171 RemoveRequest
<I
>, &RemoveRequest
<I
>::handle_detach_child
>(this);
172 auto req
= DetachChildRequest
<I
>::create(*m_image_ctx
, ctx
);
177 void RemoveRequest
<I
>::handle_detach_child(int r
) {
178 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
181 lderr(m_cct
) << "failed to detach child from parent: "
182 << cpp_strerror(r
) << dendl
;
187 send_disable_mirror();
191 void RemoveRequest
<I
>::send_disable_mirror() {
192 ldout(m_cct
, 20) << dendl
;
194 using klass
= RemoveRequest
<I
>;
195 Context
*ctx
= create_context_callback
<
196 klass
, &klass::handle_disable_mirror
>(this);
198 mirror::DisableRequest
<I
> *req
=
199 mirror::DisableRequest
<I
>::create(m_image_ctx
, m_force
, !m_force
, ctx
);
204 void RemoveRequest
<I
>::handle_disable_mirror(int r
) {
205 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
207 if (r
== -EOPNOTSUPP
) {
210 lderr(m_cct
) << "error disabling image mirroring: "
211 << cpp_strerror(r
) << dendl
;
218 void RemoveRequest
<I
>::send_close_image(int r
) {
219 ldout(m_cct
, 20) << dendl
;
222 using klass
= RemoveRequest
<I
>;
223 Context
*ctx
= create_context_callback
<
224 klass
, &klass::handle_send_close_image
>(this);
226 m_image_ctx
->state
->close(ctx
);
230 void RemoveRequest
<I
>::handle_send_close_image(int r
) {
231 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
234 lderr(m_cct
) << "error encountered while closing image: "
235 << cpp_strerror(r
) << dendl
;
238 m_image_ctx
->destroy();
239 m_image_ctx
= nullptr;
250 void RemoveRequest
<I
>::remove_header() {
251 ldout(m_cct
, 20) << dendl
;
253 using klass
= RemoveRequest
<I
>;
254 librados::AioCompletion
*rados_completion
=
255 create_rados_callback
<klass
, &klass::handle_remove_header
>(this);
256 int r
= m_ioctx
.aio_remove(m_header_oid
, rados_completion
);
258 rados_completion
->release();
262 void RemoveRequest
<I
>::handle_remove_header(int r
) {
263 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
265 if (r
< 0 && r
!= -ENOENT
) {
266 lderr(m_cct
) << "error removing header: " << cpp_strerror(r
) << dendl
;
274 void RemoveRequest
<I
>::remove_header_v2() {
275 ldout(m_cct
, 20) << dendl
;
277 if (m_header_oid
.empty()) {
278 m_header_oid
= util::header_name(m_image_id
);
281 using klass
= RemoveRequest
<I
>;
282 librados::AioCompletion
*rados_completion
=
283 create_rados_callback
<klass
, &klass::handle_remove_header_v2
>(this);
284 int r
= m_ioctx
.aio_remove(m_header_oid
, rados_completion
);
286 rados_completion
->release();
290 void RemoveRequest
<I
>::handle_remove_header_v2(int r
) {
291 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
293 if (r
< 0 && r
!= -ENOENT
) {
294 lderr(m_cct
) << "error removing header: " << cpp_strerror(r
) << dendl
;
299 send_journal_remove();
303 void RemoveRequest
<I
>::send_journal_remove() {
304 ldout(m_cct
, 20) << dendl
;
306 using klass
= RemoveRequest
<I
>;
307 Context
*ctx
= create_context_callback
<
308 klass
, &klass::handle_journal_remove
>(this);
310 journal::RemoveRequest
<I
> *req
= journal::RemoveRequest
<I
>::create(
311 m_ioctx
, m_image_id
, Journal
<>::IMAGE_CLIENT_ID
, m_op_work_queue
, ctx
);
316 void RemoveRequest
<I
>::handle_journal_remove(int r
) {
317 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
319 if (r
< 0 && r
!= -ENOENT
) {
320 lderr(m_cct
) << "failed to remove image journal: " << cpp_strerror(r
)
328 send_object_map_remove();
332 void RemoveRequest
<I
>::send_object_map_remove() {
333 ldout(m_cct
, 20) << dendl
;
335 using klass
= RemoveRequest
<I
>;
336 librados::AioCompletion
*rados_completion
=
337 create_rados_callback
<klass
, &klass::handle_object_map_remove
>(this);
339 int r
= ObjectMap
<>::aio_remove(m_ioctx
,
343 rados_completion
->release();
347 void RemoveRequest
<I
>::handle_object_map_remove(int r
) {
348 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
350 if (r
< 0 && r
!= -ENOENT
) {
351 lderr(m_cct
) << "failed to remove image journal: " << cpp_strerror(r
)
359 mirror_image_remove();
363 void RemoveRequest
<I
>::mirror_image_remove() {
364 ldout(m_cct
, 20) << dendl
;
366 librados::ObjectWriteOperation op
;
367 cls_client::mirror_image_remove(&op
, m_image_id
);
369 using klass
= RemoveRequest
<I
>;
370 librados::AioCompletion
*rados_completion
=
371 create_rados_callback
<klass
, &klass::handle_mirror_image_remove
>(this);
372 int r
= m_ioctx
.aio_operate(RBD_MIRRORING
, rados_completion
, &op
);
374 rados_completion
->release();
378 void RemoveRequest
<I
>::handle_mirror_image_remove(int r
) {
379 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
381 if (r
< 0 && r
!= -ENOENT
&& r
!= -EOPNOTSUPP
) {
382 lderr(m_cct
) << "failed to remove mirror image state: "
383 << cpp_strerror(r
) << dendl
;
388 if (m_from_trash_remove
) {
389 // both the id object and the directory entry have been removed in
390 // a previous call to trash_move.
399 void RemoveRequest
<I
>::remove_image() {
400 ldout(m_cct
, 20) << dendl
;
402 if (m_old_format
|| m_unknown_format
) {
410 void RemoveRequest
<I
>::remove_v1_image() {
411 ldout(m_cct
, 20) << dendl
;
413 Context
*ctx
= new FunctionContext([this] (int r
) {
414 r
= tmap_rm(m_ioctx
, m_image_name
);
415 handle_remove_v1_image(r
);
418 m_op_work_queue
->queue(ctx
, 0);
422 void RemoveRequest
<I
>::handle_remove_v1_image(int r
) {
423 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
425 m_old_format
= (r
== 0);
426 if (r
== 0 || (r
< 0 && !m_unknown_format
)) {
427 if (r
< 0 && r
!= -ENOENT
) {
428 lderr(m_cct
) << "error removing image from v1 directory: "
429 << cpp_strerror(r
) << dendl
;
432 m_on_finish
->complete(r
);
443 void RemoveRequest
<I
>::remove_v2_image() {
444 ldout(m_cct
, 20) << dendl
;
446 if (m_image_id
.empty()) {
449 } else if (m_image_name
.empty()) {
450 dir_get_image_name();
459 void RemoveRequest
<I
>::dir_get_image_id() {
460 ldout(m_cct
, 20) << dendl
;
462 librados::ObjectReadOperation op
;
463 librbd::cls_client::dir_get_id_start(&op
, m_image_name
);
465 using klass
= RemoveRequest
<I
>;
466 librados::AioCompletion
*rados_completion
=
467 create_rados_callback
<klass
, &klass::handle_dir_get_image_id
>(this);
469 int r
= m_ioctx
.aio_operate(RBD_DIRECTORY
, rados_completion
, &op
, &m_out_bl
);
471 rados_completion
->release();
475 void RemoveRequest
<I
>::handle_dir_get_image_id(int r
) {
476 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
478 if (r
< 0 && r
!= -ENOENT
) {
479 lderr(m_cct
) << "error fetching image id: " << cpp_strerror(r
)
486 auto iter
= m_out_bl
.cbegin();
487 r
= librbd::cls_client::dir_get_id_finish(&iter
, &m_image_id
);
498 void RemoveRequest
<I
>::dir_get_image_name() {
499 ldout(m_cct
, 20) << dendl
;
501 librados::ObjectReadOperation op
;
502 librbd::cls_client::dir_get_name_start(&op
, m_image_id
);
504 using klass
= RemoveRequest
<I
>;
505 librados::AioCompletion
*rados_completion
=
506 create_rados_callback
<klass
, &klass::handle_dir_get_image_name
>(this);
508 int r
= m_ioctx
.aio_operate(RBD_DIRECTORY
, rados_completion
, &op
, &m_out_bl
);
510 rados_completion
->release();
514 void RemoveRequest
<I
>::handle_dir_get_image_name(int r
) {
515 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
517 if (r
< 0 && r
!= -ENOENT
) {
518 lderr(m_cct
) << "error fetching image name: " << cpp_strerror(r
)
525 auto iter
= m_out_bl
.cbegin();
526 r
= librbd::cls_client::dir_get_name_finish(&iter
, &m_image_name
);
537 void RemoveRequest
<I
>::remove_id_object() {
538 ldout(m_cct
, 20) << dendl
;
540 using klass
= RemoveRequest
<I
>;
541 librados::AioCompletion
*rados_completion
=
542 create_rados_callback
<klass
, &klass::handle_remove_id_object
>(this);
543 int r
= m_ioctx
.aio_remove(util::id_obj_name(m_image_name
), rados_completion
);
545 rados_completion
->release();
549 void RemoveRequest
<I
>::handle_remove_id_object(int r
) {
550 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
552 if (r
< 0 && r
!= -ENOENT
) {
553 lderr(m_cct
) << "error removing id object: " << cpp_strerror(r
)
563 void RemoveRequest
<I
>::dir_remove_image() {
564 ldout(m_cct
, 20) << dendl
;
566 librados::ObjectWriteOperation op
;
567 librbd::cls_client::dir_remove_image(&op
, m_image_name
, m_image_id
);
569 using klass
= RemoveRequest
<I
>;
570 librados::AioCompletion
*rados_completion
=
571 create_rados_callback
<klass
, &klass::handle_dir_remove_image
>(this);
572 int r
= m_ioctx
.aio_operate(RBD_DIRECTORY
, rados_completion
, &op
);
574 rados_completion
->release();
578 void RemoveRequest
<I
>::handle_dir_remove_image(int r
) {
579 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
581 if (r
< 0 && r
!= -ENOENT
) {
582 lderr(m_cct
) << "error removing image from v2 directory: "
583 << cpp_strerror(r
) << dendl
;
590 void RemoveRequest
<I
>::finish(int r
) {
591 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
593 m_on_finish
->complete(r
);
598 } // namespace librbd
600 template class librbd::image::RemoveRequest
<librbd::ImageCtx
>;