]> git.proxmox.com Git - ceph.git/blame - ceph/src/tools/rbd_mirror/image_deleter/TrashMoveRequest.cc
import ceph 16.2.7
[ceph.git] / ceph / src / tools / rbd_mirror / image_deleter / TrashMoveRequest.cc
CommitLineData
11fdf7f2
TL
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
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"
f67539c2 9#include "common/WorkQueue.h"
11fdf7f2
TL
10#include "librbd/ExclusiveLock.h"
11#include "librbd/ImageCtx.h"
12#include "librbd/ImageState.h"
13#include "librbd/Journal.h"
14#include "librbd/TrashWatcher.h"
15#include "librbd/Utils.h"
f67539c2 16#include "librbd/asio/ContextWQ.h"
11fdf7f2 17#include "librbd/journal/ResetRequest.h"
a4b75251 18#include "librbd/mirror/ImageRemoveRequest.h"
9f95a23c 19#include "librbd/mirror/GetInfoRequest.h"
11fdf7f2
TL
20#include "librbd/trash/MoveRequest.h"
21#include "tools/rbd_mirror/image_deleter/Types.h"
22
23#define dout_context g_ceph_context
24#define dout_subsys ceph_subsys_rbd_mirror
25#undef dout_prefix
26#define dout_prefix *_dout << "rbd::mirror::image_deleter::TrashMoveRequest: " \
27 << this << " " << __func__ << ": "
28namespace rbd {
29namespace mirror {
30namespace image_deleter {
31
32using librbd::util::create_context_callback;
33using librbd::util::create_rados_callback;
34
35template <typename I>
36void TrashMoveRequest<I>::send() {
37 get_mirror_image_id();
38}
39
40template <typename I>
41void TrashMoveRequest<I>::get_mirror_image_id() {
42 dout(10) << dendl;
43
44 librados::ObjectReadOperation op;
45 librbd::cls_client::mirror_image_get_image_id_start(&op, m_global_image_id);
46
47 auto aio_comp = create_rados_callback<
48 TrashMoveRequest<I>,
49 &TrashMoveRequest<I>::handle_get_mirror_image_id>(this);
50 m_out_bl.clear();
51 int r = m_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, &m_out_bl);
52 ceph_assert(r == 0);
53 aio_comp->release();
54}
55
56template <typename I>
57void TrashMoveRequest<I>::handle_get_mirror_image_id(int r) {
58 dout(10) << "r=" << r << dendl;
59
60 if (r == 0) {
61 auto bl_it = m_out_bl.cbegin();
62 r = librbd::cls_client::mirror_image_get_image_id_finish(&bl_it,
63 &m_image_id);
64 }
65 if (r == -ENOENT) {
66 dout(10) << "image " << m_global_image_id << " is not mirrored" << dendl;
67 finish(r);
68 return;
69 } else if (r < 0) {
70 derr << "error retrieving local id for image " << m_global_image_id << ": "
71 << cpp_strerror(r) << dendl;
72 finish(r);
73 return;
74 }
75
9f95a23c 76 get_mirror_info();
11fdf7f2
TL
77}
78
79template <typename I>
9f95a23c 80void TrashMoveRequest<I>::get_mirror_info() {
11fdf7f2
TL
81 dout(10) << dendl;
82
83 auto ctx = create_context_callback<
9f95a23c
TL
84 TrashMoveRequest<I>, &TrashMoveRequest<I>::handle_get_mirror_info>(this);
85 auto req = librbd::mirror::GetInfoRequest<I>::create(
86 m_io_ctx, m_op_work_queue, m_image_id, &m_mirror_image, &m_promotion_state,
87 &m_primary_mirror_uuid, ctx);
88 req->send();
11fdf7f2
TL
89}
90
91template <typename I>
9f95a23c 92void TrashMoveRequest<I>::handle_get_mirror_info(int r) {
11fdf7f2
TL
93 dout(10) << "r=" << r << dendl;
94
9f95a23c
TL
95 if (r == -ENOENT) {
96 dout(5) << "image " << m_global_image_id << " is not mirrored" << dendl;
97 finish(r);
98 return;
99 } else if (r < 0) {
11fdf7f2
TL
100 derr << "error retrieving image primary info for image "
101 << m_global_image_id << ": " << cpp_strerror(r) << dendl;
102 finish(r);
103 return;
9f95a23c
TL
104 }
105
106 if (m_promotion_state == librbd::mirror::PROMOTION_STATE_PRIMARY) {
107 dout(10) << "image " << m_global_image_id << " is local primary" << dendl;
108 finish(-EPERM);
109 return;
110 } else if (m_promotion_state == librbd::mirror::PROMOTION_STATE_ORPHAN &&
111 !m_resync) {
112 dout(10) << "image " << m_global_image_id << " is orphaned" << dendl;
113 finish(-EPERM);
114 return;
11fdf7f2
TL
115 }
116
117 disable_mirror_image();
118}
119
120template <typename I>
121void TrashMoveRequest<I>::disable_mirror_image() {
122 dout(10) << dendl;
123
9f95a23c 124 m_mirror_image.state = cls::rbd::MIRROR_IMAGE_STATE_DISABLING;
11fdf7f2
TL
125
126 librados::ObjectWriteOperation op;
9f95a23c 127 librbd::cls_client::mirror_image_set(&op, m_image_id, m_mirror_image);
11fdf7f2
TL
128
129 auto aio_comp = create_rados_callback<
130 TrashMoveRequest<I>,
131 &TrashMoveRequest<I>::handle_disable_mirror_image>(this);
132 int r = m_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op);
133 ceph_assert(r == 0);
134 aio_comp->release();
135}
136
137template <typename I>
138void TrashMoveRequest<I>::handle_disable_mirror_image(int r) {
139 dout(10) << "r=" << r << dendl;
140
141 if (r == -ENOENT) {
142 dout(10) << "local image is not mirrored, aborting deletion." << dendl;
143 finish(r);
144 return;
145 } else if (r == -EEXIST || r == -EINVAL) {
146 derr << "cannot disable mirroring for image " << m_global_image_id
147 << ": global_image_id has changed/reused: "
148 << cpp_strerror(r) << dendl;
149 finish(r);
150 return;
151 } else if (r < 0) {
152 derr << "cannot disable mirroring for image " << m_global_image_id
153 << ": " << cpp_strerror(r) << dendl;
154 finish(r);
155 return;
156 }
157
11fdf7f2
TL
158 open_image();
159}
160
161template <typename I>
162void TrashMoveRequest<I>::open_image() {
163 dout(10) << dendl;
164
165 m_image_ctx = I::create("", m_image_id, nullptr, m_io_ctx, false);
166
9f95a23c
TL
167 // ensure non-primary images can be modified
168 m_image_ctx->read_only_mask &= ~librbd::IMAGE_READ_ONLY_FLAG_NON_PRIMARY;
169
11fdf7f2
TL
170 {
171 // don't attempt to open the journal
9f95a23c 172 std::unique_lock image_locker{m_image_ctx->image_lock};
11fdf7f2
TL
173 m_image_ctx->set_journal_policy(new JournalPolicy());
174 }
175
176 Context *ctx = create_context_callback<
177 TrashMoveRequest<I>, &TrashMoveRequest<I>::handle_open_image>(this);
178 m_image_ctx->state->open(librbd::OPEN_FLAG_SKIP_OPEN_PARENT, ctx);
179}
180
181template <typename I>
182void TrashMoveRequest<I>::handle_open_image(int r) {
183 dout(10) << "r=" << r << dendl;
184
a4b75251
TL
185 if (r == -ENOENT) {
186 dout(5) << "mirror image does not exist, removing orphaned metadata" << dendl;
187 m_image_ctx = nullptr;
188 remove_mirror_image();
189 return;
190 }
191
11fdf7f2
TL
192 if (r < 0) {
193 derr << "failed to open image: " << cpp_strerror(r) << dendl;
11fdf7f2
TL
194 m_image_ctx = nullptr;
195 finish(r);
196 return;
197 }
198
199 if (m_image_ctx->old_format) {
200 derr << "cannot move v1 image to trash" << dendl;
201 m_ret_val = -EINVAL;
202 close_image();
203 return;
204 }
205
9f95a23c
TL
206 reset_journal();
207}
208
209template <typename I>
210void TrashMoveRequest<I>::reset_journal() {
211 if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) {
212 // snapshot-based mirroring doesn't require journal feature
213 acquire_lock();
214 return;
215 }
216
217 dout(10) << dendl;
218
f67539c2
TL
219 // TODO use Journal thread pool for journal ops until converted to ASIO
220 ContextWQ* context_wq;
221 librbd::Journal<>::get_work_queue(
222 reinterpret_cast<CephContext*>(m_io_ctx.cct()), &context_wq);
223
9f95a23c
TL
224 // ensure that if the image is recovered any peers will split-brain
225 auto ctx = create_context_callback<
226 TrashMoveRequest<I>, &TrashMoveRequest<I>::handle_reset_journal>(this);
227 auto req = librbd::journal::ResetRequest<I>::create(
228 m_io_ctx, m_image_id, librbd::Journal<>::IMAGE_CLIENT_ID,
f67539c2 229 librbd::Journal<>::LOCAL_MIRROR_UUID, context_wq, ctx);
9f95a23c
TL
230 req->send();
231}
232
233template <typename I>
234void TrashMoveRequest<I>::handle_reset_journal(int r) {
235 dout(10) << "r=" << r << dendl;
236
237 if (r < 0 && r != -ENOENT) {
238 derr << "failed to reset journal: " << cpp_strerror(r) << dendl;
239 m_ret_val = r;
240 close_image();
241 return;
242 }
243
11fdf7f2
TL
244 acquire_lock();
245}
246
247template <typename I>
248void TrashMoveRequest<I>::acquire_lock() {
9f95a23c 249 m_image_ctx->owner_lock.lock_shared();
11fdf7f2 250 if (m_image_ctx->exclusive_lock == nullptr) {
9f95a23c
TL
251 m_image_ctx->owner_lock.unlock_shared();
252
253 if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) {
254 // snapshot-based mirroring doesn't require exclusive-lock
255 trash_move();
256 } else {
257 derr << "exclusive lock feature not enabled" << dendl;
258 m_ret_val = -EINVAL;
259 close_image();
260 }
11fdf7f2
TL
261 return;
262 }
263
264 dout(10) << dendl;
265
266 Context *ctx = create_context_callback<
267 TrashMoveRequest<I>, &TrashMoveRequest<I>::handle_acquire_lock>(this);
268 m_image_ctx->exclusive_lock->block_requests(0);
269 m_image_ctx->exclusive_lock->acquire_lock(ctx);
9f95a23c 270 m_image_ctx->owner_lock.unlock_shared();
11fdf7f2
TL
271}
272
273template <typename I>
274void TrashMoveRequest<I>::handle_acquire_lock(int r) {
275 dout(10) << "r=" << r << dendl;
276
277 if (r < 0) {
278 derr << "failed to acquire exclusive lock: " << cpp_strerror(r) << dendl;
279 m_ret_val = r;
280 close_image();
281 return;
282 }
283
284 trash_move();
285}
286
287template <typename I>
288void TrashMoveRequest<I>::trash_move() {
289 dout(10) << dendl;
290
291 utime_t delete_time{ceph_clock_now()};
292 utime_t deferment_end_time{delete_time};
293 deferment_end_time +=
294 m_image_ctx->config.template get_val<uint64_t>("rbd_mirroring_delete_delay");
295
296 m_trash_image_spec = {
297 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, m_image_ctx->name, delete_time,
298 deferment_end_time};
299
300 Context *ctx = create_context_callback<
301 TrashMoveRequest<I>, &TrashMoveRequest<I>::handle_trash_move>(this);
302 auto req = librbd::trash::MoveRequest<I>::create(
303 m_io_ctx, m_image_id, m_trash_image_spec, ctx);
304 req->send();
305}
306
307template <typename I>
308void TrashMoveRequest<I>::handle_trash_move(int r) {
309 dout(10) << "r=" << r << dendl;
310
311 if (r < 0) {
312 derr << "failed to move image to trash: " << cpp_strerror(r) << dendl;
313 m_ret_val = r;
314 close_image();
315 return;
316 }
317
318 m_moved_to_trash = true;
319 remove_mirror_image();
320}
321
322template <typename I>
323void TrashMoveRequest<I>::remove_mirror_image() {
324 dout(10) << dendl;
325
a4b75251 326 auto ctx = create_context_callback<
11fdf7f2
TL
327 TrashMoveRequest<I>,
328 &TrashMoveRequest<I>::handle_remove_mirror_image>(this);
a4b75251
TL
329 auto req = librbd::mirror::ImageRemoveRequest<I>::create(
330 m_io_ctx, m_global_image_id, m_image_id, ctx);
331 req->send();
11fdf7f2
TL
332}
333
334template <typename I>
335void TrashMoveRequest<I>::handle_remove_mirror_image(int r) {
336 dout(10) << "r=" << r << dendl;
337
338 if (r == -ENOENT) {
339 dout(10) << "local image is not mirrored" << dendl;
340 } else if (r < 0) {
341 derr << "failed to remove mirror image state for " << m_global_image_id
342 << ": " << cpp_strerror(r) << dendl;
343 m_ret_val = r;
344 }
345
346 close_image();
347}
348
349template <typename I>
350void TrashMoveRequest<I>::close_image() {
351 dout(10) << dendl;
352
a4b75251
TL
353 if (m_image_ctx == nullptr) {
354 handle_close_image(0);
355 return;
356 }
11fdf7f2
TL
357 Context *ctx = create_context_callback<
358 TrashMoveRequest<I>, &TrashMoveRequest<I>::handle_close_image>(this);
359 m_image_ctx->state->close(ctx);
360}
361
362template <typename I>
363void TrashMoveRequest<I>::handle_close_image(int r) {
364 dout(10) << "r=" << r << dendl;
365
11fdf7f2
TL
366 m_image_ctx = nullptr;
367
368 if (r < 0) {
369 derr << "failed to close image: " << cpp_strerror(r) << dendl;
370 }
371
372 // don't send notification if we failed
373 if (!m_moved_to_trash) {
374 finish(0);
375 return;
376 }
377
378 notify_trash_add();
379}
380
381template <typename I>
382void TrashMoveRequest<I>::notify_trash_add() {
383 dout(10) << dendl;
384
385 Context *ctx = create_context_callback<
386 TrashMoveRequest<I>, &TrashMoveRequest<I>::handle_notify_trash_add>(this);
387 librbd::TrashWatcher<I>::notify_image_added(m_io_ctx, m_image_id,
388 m_trash_image_spec, ctx);
389}
390
391template <typename I>
392void TrashMoveRequest<I>::handle_notify_trash_add(int r) {
393 dout(10) << "r=" << r << dendl;
394
395 if (r < 0) {
396 derr << "failed to notify trash watchers: " << cpp_strerror(r) << dendl;
397 }
398
399 finish(0);
400}
401
402template <typename I>
403void TrashMoveRequest<I>::finish(int r) {
404 if (m_ret_val < 0) {
405 r = m_ret_val;
406 }
407
408 dout(10) << "r=" << r << dendl;
409
410 m_on_finish->complete(r);
411 delete this;
412}
413
414} // namespace image_deleter
415} // namespace mirror
416} // namespace rbd
417
418template class rbd::mirror::image_deleter::TrashMoveRequest<librbd::ImageCtx>;
419