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
;
129 if (!m_image_ctx
->data_ctx
.is_valid()) {
138 void RemoveRequest
<I
>::trim_image() {
139 ldout(m_cct
, 20) << dendl
;
141 using klass
= RemoveRequest
<I
>;
142 Context
*ctx
= create_async_context_callback(
143 *m_image_ctx
, create_context_callback
<
144 klass
, &klass::handle_trim_image
>(this));
146 RWLock::RLocker
owner_lock(m_image_ctx
->owner_lock
);
147 auto req
= librbd::operation::TrimRequest
<I
>::create(
148 *m_image_ctx
, ctx
, m_image_ctx
->size
, 0, m_prog_ctx
);
153 void RemoveRequest
<I
>::handle_trim_image(int r
) {
154 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
157 lderr(m_cct
) << "failed to remove some object(s): "
158 << cpp_strerror(r
) << dendl
;
172 void RemoveRequest
<I
>::detach_child() {
173 ldout(m_cct
, 20) << dendl
;
175 auto ctx
= create_context_callback
<
176 RemoveRequest
<I
>, &RemoveRequest
<I
>::handle_detach_child
>(this);
177 auto req
= DetachChildRequest
<I
>::create(*m_image_ctx
, ctx
);
182 void RemoveRequest
<I
>::handle_detach_child(int r
) {
183 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
186 lderr(m_cct
) << "failed to detach child from parent: "
187 << cpp_strerror(r
) << dendl
;
192 send_disable_mirror();
196 void RemoveRequest
<I
>::send_disable_mirror() {
197 ldout(m_cct
, 20) << dendl
;
199 using klass
= RemoveRequest
<I
>;
200 Context
*ctx
= create_context_callback
<
201 klass
, &klass::handle_disable_mirror
>(this);
203 mirror::DisableRequest
<I
> *req
=
204 mirror::DisableRequest
<I
>::create(m_image_ctx
, m_force
, !m_force
, ctx
);
209 void RemoveRequest
<I
>::handle_disable_mirror(int r
) {
210 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
212 if (r
== -EOPNOTSUPP
) {
215 lderr(m_cct
) << "error disabling image mirroring: "
216 << cpp_strerror(r
) << dendl
;
223 void RemoveRequest
<I
>::send_close_image(int r
) {
224 ldout(m_cct
, 20) << dendl
;
227 using klass
= RemoveRequest
<I
>;
228 Context
*ctx
= create_context_callback
<
229 klass
, &klass::handle_send_close_image
>(this);
231 m_image_ctx
->state
->close(ctx
);
235 void RemoveRequest
<I
>::handle_send_close_image(int r
) {
236 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
239 lderr(m_cct
) << "error encountered while closing image: "
240 << cpp_strerror(r
) << dendl
;
243 m_image_ctx
->destroy();
244 m_image_ctx
= nullptr;
255 void RemoveRequest
<I
>::remove_header() {
256 ldout(m_cct
, 20) << dendl
;
258 using klass
= RemoveRequest
<I
>;
259 librados::AioCompletion
*rados_completion
=
260 create_rados_callback
<klass
, &klass::handle_remove_header
>(this);
261 int r
= m_ioctx
.aio_remove(m_header_oid
, rados_completion
);
263 rados_completion
->release();
267 void RemoveRequest
<I
>::handle_remove_header(int r
) {
268 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
270 if (r
< 0 && r
!= -ENOENT
) {
271 lderr(m_cct
) << "error removing header: " << cpp_strerror(r
) << dendl
;
279 void RemoveRequest
<I
>::remove_header_v2() {
280 ldout(m_cct
, 20) << dendl
;
282 if (m_header_oid
.empty()) {
283 m_header_oid
= util::header_name(m_image_id
);
286 using klass
= RemoveRequest
<I
>;
287 librados::AioCompletion
*rados_completion
=
288 create_rados_callback
<klass
, &klass::handle_remove_header_v2
>(this);
289 int r
= m_ioctx
.aio_remove(m_header_oid
, rados_completion
);
291 rados_completion
->release();
295 void RemoveRequest
<I
>::handle_remove_header_v2(int r
) {
296 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
298 if (r
< 0 && r
!= -ENOENT
) {
299 lderr(m_cct
) << "error removing header: " << cpp_strerror(r
) << dendl
;
304 send_journal_remove();
308 void RemoveRequest
<I
>::send_journal_remove() {
309 ldout(m_cct
, 20) << dendl
;
311 using klass
= RemoveRequest
<I
>;
312 Context
*ctx
= create_context_callback
<
313 klass
, &klass::handle_journal_remove
>(this);
315 journal::RemoveRequest
<I
> *req
= journal::RemoveRequest
<I
>::create(
316 m_ioctx
, m_image_id
, Journal
<>::IMAGE_CLIENT_ID
, m_op_work_queue
, ctx
);
321 void RemoveRequest
<I
>::handle_journal_remove(int r
) {
322 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
324 if (r
< 0 && r
!= -ENOENT
) {
325 lderr(m_cct
) << "failed to remove image journal: " << cpp_strerror(r
)
333 send_object_map_remove();
337 void RemoveRequest
<I
>::send_object_map_remove() {
338 ldout(m_cct
, 20) << dendl
;
340 using klass
= RemoveRequest
<I
>;
341 librados::AioCompletion
*rados_completion
=
342 create_rados_callback
<klass
, &klass::handle_object_map_remove
>(this);
344 int r
= ObjectMap
<>::aio_remove(m_ioctx
,
348 rados_completion
->release();
352 void RemoveRequest
<I
>::handle_object_map_remove(int r
) {
353 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
355 if (r
< 0 && r
!= -ENOENT
) {
356 lderr(m_cct
) << "failed to remove image journal: " << cpp_strerror(r
)
364 mirror_image_remove();
368 void RemoveRequest
<I
>::mirror_image_remove() {
369 ldout(m_cct
, 20) << dendl
;
371 librados::ObjectWriteOperation op
;
372 cls_client::mirror_image_remove(&op
, m_image_id
);
374 using klass
= RemoveRequest
<I
>;
375 librados::AioCompletion
*rados_completion
=
376 create_rados_callback
<klass
, &klass::handle_mirror_image_remove
>(this);
377 int r
= m_ioctx
.aio_operate(RBD_MIRRORING
, rados_completion
, &op
);
379 rados_completion
->release();
383 void RemoveRequest
<I
>::handle_mirror_image_remove(int r
) {
384 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
386 if (r
< 0 && r
!= -ENOENT
&& r
!= -EOPNOTSUPP
) {
387 lderr(m_cct
) << "failed to remove mirror image state: "
388 << cpp_strerror(r
) << dendl
;
393 if (m_from_trash_remove
) {
394 // both the id object and the directory entry have been removed in
395 // a previous call to trash_move.
404 void RemoveRequest
<I
>::remove_image() {
405 ldout(m_cct
, 20) << dendl
;
407 if (m_old_format
|| m_unknown_format
) {
415 void RemoveRequest
<I
>::remove_v1_image() {
416 ldout(m_cct
, 20) << dendl
;
418 Context
*ctx
= new FunctionContext([this] (int r
) {
419 r
= tmap_rm(m_ioctx
, m_image_name
);
420 handle_remove_v1_image(r
);
423 m_op_work_queue
->queue(ctx
, 0);
427 void RemoveRequest
<I
>::handle_remove_v1_image(int r
) {
428 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
430 m_old_format
= (r
== 0);
431 if (r
== 0 || (r
< 0 && !m_unknown_format
)) {
432 if (r
< 0 && r
!= -ENOENT
) {
433 lderr(m_cct
) << "error removing image from v1 directory: "
434 << cpp_strerror(r
) << dendl
;
437 m_on_finish
->complete(r
);
448 void RemoveRequest
<I
>::remove_v2_image() {
449 ldout(m_cct
, 20) << dendl
;
451 if (m_image_id
.empty()) {
454 } else if (m_image_name
.empty()) {
455 dir_get_image_name();
464 void RemoveRequest
<I
>::dir_get_image_id() {
465 ldout(m_cct
, 20) << dendl
;
467 librados::ObjectReadOperation op
;
468 librbd::cls_client::dir_get_id_start(&op
, m_image_name
);
470 using klass
= RemoveRequest
<I
>;
471 librados::AioCompletion
*rados_completion
=
472 create_rados_callback
<klass
, &klass::handle_dir_get_image_id
>(this);
474 int r
= m_ioctx
.aio_operate(RBD_DIRECTORY
, rados_completion
, &op
, &m_out_bl
);
476 rados_completion
->release();
480 void RemoveRequest
<I
>::handle_dir_get_image_id(int r
) {
481 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
483 if (r
< 0 && r
!= -ENOENT
) {
484 lderr(m_cct
) << "error fetching image id: " << cpp_strerror(r
)
491 auto iter
= m_out_bl
.cbegin();
492 r
= librbd::cls_client::dir_get_id_finish(&iter
, &m_image_id
);
503 void RemoveRequest
<I
>::dir_get_image_name() {
504 ldout(m_cct
, 20) << dendl
;
506 librados::ObjectReadOperation op
;
507 librbd::cls_client::dir_get_name_start(&op
, m_image_id
);
509 using klass
= RemoveRequest
<I
>;
510 librados::AioCompletion
*rados_completion
=
511 create_rados_callback
<klass
, &klass::handle_dir_get_image_name
>(this);
513 int r
= m_ioctx
.aio_operate(RBD_DIRECTORY
, rados_completion
, &op
, &m_out_bl
);
515 rados_completion
->release();
519 void RemoveRequest
<I
>::handle_dir_get_image_name(int r
) {
520 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
522 if (r
< 0 && r
!= -ENOENT
) {
523 lderr(m_cct
) << "error fetching image name: " << cpp_strerror(r
)
530 auto iter
= m_out_bl
.cbegin();
531 r
= librbd::cls_client::dir_get_name_finish(&iter
, &m_image_name
);
542 void RemoveRequest
<I
>::remove_id_object() {
543 ldout(m_cct
, 20) << dendl
;
545 using klass
= RemoveRequest
<I
>;
546 librados::AioCompletion
*rados_completion
=
547 create_rados_callback
<klass
, &klass::handle_remove_id_object
>(this);
548 int r
= m_ioctx
.aio_remove(util::id_obj_name(m_image_name
), rados_completion
);
550 rados_completion
->release();
554 void RemoveRequest
<I
>::handle_remove_id_object(int r
) {
555 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
557 if (r
< 0 && r
!= -ENOENT
) {
558 lderr(m_cct
) << "error removing id object: " << cpp_strerror(r
)
568 void RemoveRequest
<I
>::dir_remove_image() {
569 ldout(m_cct
, 20) << dendl
;
571 librados::ObjectWriteOperation op
;
572 librbd::cls_client::dir_remove_image(&op
, m_image_name
, m_image_id
);
574 using klass
= RemoveRequest
<I
>;
575 librados::AioCompletion
*rados_completion
=
576 create_rados_callback
<klass
, &klass::handle_dir_remove_image
>(this);
577 int r
= m_ioctx
.aio_operate(RBD_DIRECTORY
, rados_completion
, &op
);
579 rados_completion
->release();
583 void RemoveRequest
<I
>::handle_dir_remove_image(int r
) {
584 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
586 if (r
< 0 && r
!= -ENOENT
) {
587 lderr(m_cct
) << "error removing image from v2 directory: "
588 << cpp_strerror(r
) << dendl
;
595 void RemoveRequest
<I
>::finish(int r
) {
596 ldout(m_cct
, 20) << "r=" << r
<< dendl
;
598 m_on_finish
->complete(r
);
603 } // namespace librbd
605 template class librbd::image::RemoveRequest
<librbd::ImageCtx
>;