1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "tools/rbd_mirror/image_deleter/TrashMoveRequest.h"
5 #include "include/rbd_types.h"
6 #include "cls/rbd/cls_rbd_client.h"
7 #include "common/debug.h"
8 #include "common/errno.h"
9 #include "librbd/ExclusiveLock.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/ImageState.h"
12 #include "librbd/Journal.h"
13 #include "librbd/TrashWatcher.h"
14 #include "librbd/Utils.h"
15 #include "librbd/journal/ResetRequest.h"
16 #include "librbd/trash/MoveRequest.h"
17 #include "tools/rbd_mirror/image_deleter/Types.h"
19 #define dout_context g_ceph_context
20 #define dout_subsys ceph_subsys_rbd_mirror
22 #define dout_prefix *_dout << "rbd::mirror::image_deleter::TrashMoveRequest: " \
23 << this << " " << __func__ << ": "
26 namespace image_deleter
{
28 using librbd::util::create_context_callback
;
29 using librbd::util::create_rados_callback
;
32 void TrashMoveRequest
<I
>::send() {
33 get_mirror_image_id();
37 void TrashMoveRequest
<I
>::get_mirror_image_id() {
40 librados::ObjectReadOperation op
;
41 librbd::cls_client::mirror_image_get_image_id_start(&op
, m_global_image_id
);
43 auto aio_comp
= create_rados_callback
<
45 &TrashMoveRequest
<I
>::handle_get_mirror_image_id
>(this);
47 int r
= m_io_ctx
.aio_operate(RBD_MIRRORING
, aio_comp
, &op
, &m_out_bl
);
53 void TrashMoveRequest
<I
>::handle_get_mirror_image_id(int r
) {
54 dout(10) << "r=" << r
<< dendl
;
57 auto bl_it
= m_out_bl
.cbegin();
58 r
= librbd::cls_client::mirror_image_get_image_id_finish(&bl_it
,
62 dout(10) << "image " << m_global_image_id
<< " is not mirrored" << dendl
;
66 derr
<< "error retrieving local id for image " << m_global_image_id
<< ": "
67 << cpp_strerror(r
) << dendl
;
76 void TrashMoveRequest
<I
>::get_tag_owner() {
79 auto ctx
= create_context_callback
<
80 TrashMoveRequest
<I
>, &TrashMoveRequest
<I
>::handle_get_tag_owner
>(this);
81 librbd::Journal
<I
>::get_tag_owner(m_io_ctx
, m_image_id
, &m_mirror_uuid
,
82 m_op_work_queue
, ctx
);
86 void TrashMoveRequest
<I
>::handle_get_tag_owner(int r
) {
87 dout(10) << "r=" << r
<< dendl
;
89 if (r
< 0 && r
!= -ENOENT
) {
90 derr
<< "error retrieving image primary info for image "
91 << m_global_image_id
<< ": " << cpp_strerror(r
) << dendl
;
94 } else if (r
!= -ENOENT
) {
95 if (m_mirror_uuid
== librbd::Journal
<>::LOCAL_MIRROR_UUID
) {
96 dout(10) << "image " << m_global_image_id
<< " is local primary" << dendl
;
99 } else if (m_mirror_uuid
== librbd::Journal
<>::ORPHAN_MIRROR_UUID
&&
101 dout(10) << "image " << m_global_image_id
<< " is orphaned" << dendl
;
107 disable_mirror_image();
110 template <typename I
>
111 void TrashMoveRequest
<I
>::disable_mirror_image() {
114 cls::rbd::MirrorImage mirror_image
;
115 mirror_image
.global_image_id
= m_global_image_id
;
116 mirror_image
.state
= cls::rbd::MIRROR_IMAGE_STATE_DISABLING
;
118 librados::ObjectWriteOperation op
;
119 librbd::cls_client::mirror_image_set(&op
, m_image_id
, mirror_image
);
121 auto aio_comp
= create_rados_callback
<
123 &TrashMoveRequest
<I
>::handle_disable_mirror_image
>(this);
124 int r
= m_io_ctx
.aio_operate(RBD_MIRRORING
, aio_comp
, &op
);
129 template <typename I
>
130 void TrashMoveRequest
<I
>::handle_disable_mirror_image(int r
) {
131 dout(10) << "r=" << r
<< dendl
;
134 dout(10) << "local image is not mirrored, aborting deletion." << dendl
;
137 } else if (r
== -EEXIST
|| r
== -EINVAL
) {
138 derr
<< "cannot disable mirroring for image " << m_global_image_id
139 << ": global_image_id has changed/reused: "
140 << cpp_strerror(r
) << dendl
;
144 derr
<< "cannot disable mirroring for image " << m_global_image_id
145 << ": " << cpp_strerror(r
) << dendl
;
153 template <typename I
>
154 void TrashMoveRequest
<I
>::reset_journal() {
157 // ensure that if the image is recovered any peers will split-brain
158 auto ctx
= create_context_callback
<
159 TrashMoveRequest
<I
>, &TrashMoveRequest
<I
>::handle_reset_journal
>(this);
160 auto req
= librbd::journal::ResetRequest
<I
>::create(
161 m_io_ctx
, m_image_id
, librbd::Journal
<>::IMAGE_CLIENT_ID
,
162 librbd::Journal
<>::LOCAL_MIRROR_UUID
, m_op_work_queue
, ctx
);
166 template <typename I
>
167 void TrashMoveRequest
<I
>::handle_reset_journal(int r
) {
168 dout(10) << "r=" << r
<< dendl
;
170 if (r
< 0 && r
!= -ENOENT
) {
171 derr
<< "failed to reset journal: " << cpp_strerror(r
) << dendl
;
179 template <typename I
>
180 void TrashMoveRequest
<I
>::open_image() {
183 m_image_ctx
= I::create("", m_image_id
, nullptr, m_io_ctx
, false);
186 // don't attempt to open the journal
187 RWLock::WLocker
snap_locker(m_image_ctx
->snap_lock
);
188 m_image_ctx
->set_journal_policy(new JournalPolicy());
191 Context
*ctx
= create_context_callback
<
192 TrashMoveRequest
<I
>, &TrashMoveRequest
<I
>::handle_open_image
>(this);
193 m_image_ctx
->state
->open(librbd::OPEN_FLAG_SKIP_OPEN_PARENT
, ctx
);
196 template <typename I
>
197 void TrashMoveRequest
<I
>::handle_open_image(int r
) {
198 dout(10) << "r=" << r
<< dendl
;
201 derr
<< "failed to open image: " << cpp_strerror(r
) << dendl
;
202 m_image_ctx
->destroy();
203 m_image_ctx
= nullptr;
208 if (m_image_ctx
->old_format
) {
209 derr
<< "cannot move v1 image to trash" << dendl
;
218 template <typename I
>
219 void TrashMoveRequest
<I
>::acquire_lock() {
220 m_image_ctx
->owner_lock
.get_read();
221 if (m_image_ctx
->exclusive_lock
== nullptr) {
222 derr
<< "exclusive lock feature not enabled" << dendl
;
223 m_image_ctx
->owner_lock
.put_read();
231 Context
*ctx
= create_context_callback
<
232 TrashMoveRequest
<I
>, &TrashMoveRequest
<I
>::handle_acquire_lock
>(this);
233 m_image_ctx
->exclusive_lock
->block_requests(0);
234 m_image_ctx
->exclusive_lock
->acquire_lock(ctx
);
235 m_image_ctx
->owner_lock
.put_read();
238 template <typename I
>
239 void TrashMoveRequest
<I
>::handle_acquire_lock(int r
) {
240 dout(10) << "r=" << r
<< dendl
;
243 derr
<< "failed to acquire exclusive lock: " << cpp_strerror(r
) << dendl
;
252 template <typename I
>
253 void TrashMoveRequest
<I
>::trash_move() {
256 utime_t delete_time
{ceph_clock_now()};
257 utime_t deferment_end_time
{delete_time
};
258 deferment_end_time
+=
259 m_image_ctx
->config
.template get_val
<uint64_t>("rbd_mirroring_delete_delay");
261 m_trash_image_spec
= {
262 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING
, m_image_ctx
->name
, delete_time
,
265 Context
*ctx
= create_context_callback
<
266 TrashMoveRequest
<I
>, &TrashMoveRequest
<I
>::handle_trash_move
>(this);
267 auto req
= librbd::trash::MoveRequest
<I
>::create(
268 m_io_ctx
, m_image_id
, m_trash_image_spec
, ctx
);
272 template <typename I
>
273 void TrashMoveRequest
<I
>::handle_trash_move(int r
) {
274 dout(10) << "r=" << r
<< dendl
;
277 derr
<< "failed to move image to trash: " << cpp_strerror(r
) << dendl
;
283 m_moved_to_trash
= true;
284 remove_mirror_image();
287 template <typename I
>
288 void TrashMoveRequest
<I
>::remove_mirror_image() {
291 librados::ObjectWriteOperation op
;
292 librbd::cls_client::mirror_image_remove(&op
, m_image_id
);
294 auto aio_comp
= create_rados_callback
<
296 &TrashMoveRequest
<I
>::handle_remove_mirror_image
>(this);
297 int r
= m_io_ctx
.aio_operate(RBD_MIRRORING
, aio_comp
, &op
);
302 template <typename I
>
303 void TrashMoveRequest
<I
>::handle_remove_mirror_image(int r
) {
304 dout(10) << "r=" << r
<< dendl
;
307 dout(10) << "local image is not mirrored" << dendl
;
309 derr
<< "failed to remove mirror image state for " << m_global_image_id
310 << ": " << cpp_strerror(r
) << dendl
;
317 template <typename I
>
318 void TrashMoveRequest
<I
>::close_image() {
321 Context
*ctx
= create_context_callback
<
322 TrashMoveRequest
<I
>, &TrashMoveRequest
<I
>::handle_close_image
>(this);
323 m_image_ctx
->state
->close(ctx
);
326 template <typename I
>
327 void TrashMoveRequest
<I
>::handle_close_image(int r
) {
328 dout(10) << "r=" << r
<< dendl
;
330 m_image_ctx
->destroy();
331 m_image_ctx
= nullptr;
334 derr
<< "failed to close image: " << cpp_strerror(r
) << dendl
;
337 // don't send notification if we failed
338 if (!m_moved_to_trash
) {
346 template <typename I
>
347 void TrashMoveRequest
<I
>::notify_trash_add() {
350 Context
*ctx
= create_context_callback
<
351 TrashMoveRequest
<I
>, &TrashMoveRequest
<I
>::handle_notify_trash_add
>(this);
352 librbd::TrashWatcher
<I
>::notify_image_added(m_io_ctx
, m_image_id
,
353 m_trash_image_spec
, ctx
);
356 template <typename I
>
357 void TrashMoveRequest
<I
>::handle_notify_trash_add(int r
) {
358 dout(10) << "r=" << r
<< dendl
;
361 derr
<< "failed to notify trash watchers: " << cpp_strerror(r
) << dendl
;
367 template <typename I
>
368 void TrashMoveRequest
<I
>::finish(int r
) {
373 dout(10) << "r=" << r
<< dendl
;
375 m_on_finish
->complete(r
);
379 } // namespace image_deleter
380 } // namespace mirror
383 template class rbd::mirror::image_deleter::TrashMoveRequest
<librbd::ImageCtx
>;