]> git.proxmox.com Git - ceph.git/blob - ceph/src/tools/rbd_mirror/image_deleter/TrashMoveRequest.cc
import ceph 14.2.5
[ceph.git] / ceph / src / tools / rbd_mirror / image_deleter / TrashMoveRequest.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 "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"
18
19 #define dout_context g_ceph_context
20 #define dout_subsys ceph_subsys_rbd_mirror
21 #undef dout_prefix
22 #define dout_prefix *_dout << "rbd::mirror::image_deleter::TrashMoveRequest: " \
23 << this << " " << __func__ << ": "
24 namespace rbd {
25 namespace mirror {
26 namespace image_deleter {
27
28 using librbd::util::create_context_callback;
29 using librbd::util::create_rados_callback;
30
31 template <typename I>
32 void TrashMoveRequest<I>::send() {
33 get_mirror_image_id();
34 }
35
36 template <typename I>
37 void TrashMoveRequest<I>::get_mirror_image_id() {
38 dout(10) << dendl;
39
40 librados::ObjectReadOperation op;
41 librbd::cls_client::mirror_image_get_image_id_start(&op, m_global_image_id);
42
43 auto aio_comp = create_rados_callback<
44 TrashMoveRequest<I>,
45 &TrashMoveRequest<I>::handle_get_mirror_image_id>(this);
46 m_out_bl.clear();
47 int r = m_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op, &m_out_bl);
48 ceph_assert(r == 0);
49 aio_comp->release();
50 }
51
52 template <typename I>
53 void TrashMoveRequest<I>::handle_get_mirror_image_id(int r) {
54 dout(10) << "r=" << r << dendl;
55
56 if (r == 0) {
57 auto bl_it = m_out_bl.cbegin();
58 r = librbd::cls_client::mirror_image_get_image_id_finish(&bl_it,
59 &m_image_id);
60 }
61 if (r == -ENOENT) {
62 dout(10) << "image " << m_global_image_id << " is not mirrored" << dendl;
63 finish(r);
64 return;
65 } else if (r < 0) {
66 derr << "error retrieving local id for image " << m_global_image_id << ": "
67 << cpp_strerror(r) << dendl;
68 finish(r);
69 return;
70 }
71
72 get_tag_owner();
73 }
74
75 template <typename I>
76 void TrashMoveRequest<I>::get_tag_owner() {
77 dout(10) << dendl;
78
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);
83 }
84
85 template <typename I>
86 void TrashMoveRequest<I>::handle_get_tag_owner(int r) {
87 dout(10) << "r=" << r << dendl;
88
89 if (r < 0 && r != -ENOENT) {
90 derr << "error retrieving image primary info for image "
91 << m_global_image_id << ": " << cpp_strerror(r) << dendl;
92 finish(r);
93 return;
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;
97 finish(-EPERM);
98 return;
99 } else if (m_mirror_uuid == librbd::Journal<>::ORPHAN_MIRROR_UUID &&
100 !m_resync) {
101 dout(10) << "image " << m_global_image_id << " is orphaned" << dendl;
102 finish(-EPERM);
103 return;
104 }
105 }
106
107 disable_mirror_image();
108 }
109
110 template <typename I>
111 void TrashMoveRequest<I>::disable_mirror_image() {
112 dout(10) << dendl;
113
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;
117
118 librados::ObjectWriteOperation op;
119 librbd::cls_client::mirror_image_set(&op, m_image_id, mirror_image);
120
121 auto aio_comp = create_rados_callback<
122 TrashMoveRequest<I>,
123 &TrashMoveRequest<I>::handle_disable_mirror_image>(this);
124 int r = m_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op);
125 ceph_assert(r == 0);
126 aio_comp->release();
127 }
128
129 template <typename I>
130 void TrashMoveRequest<I>::handle_disable_mirror_image(int r) {
131 dout(10) << "r=" << r << dendl;
132
133 if (r == -ENOENT) {
134 dout(10) << "local image is not mirrored, aborting deletion." << dendl;
135 finish(r);
136 return;
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;
141 finish(r);
142 return;
143 } else if (r < 0) {
144 derr << "cannot disable mirroring for image " << m_global_image_id
145 << ": " << cpp_strerror(r) << dendl;
146 finish(r);
147 return;
148 }
149
150 reset_journal();
151 }
152
153 template <typename I>
154 void TrashMoveRequest<I>::reset_journal() {
155 dout(10) << dendl;
156
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);
163 req->send();
164 }
165
166 template <typename I>
167 void TrashMoveRequest<I>::handle_reset_journal(int r) {
168 dout(10) << "r=" << r << dendl;
169
170 if (r < 0 && r != -ENOENT) {
171 derr << "failed to reset journal: " << cpp_strerror(r) << dendl;
172 finish(r);
173 return;
174 }
175
176 open_image();
177 }
178
179 template <typename I>
180 void TrashMoveRequest<I>::open_image() {
181 dout(10) << dendl;
182
183 m_image_ctx = I::create("", m_image_id, nullptr, m_io_ctx, false);
184
185 {
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());
189 }
190
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);
194 }
195
196 template <typename I>
197 void TrashMoveRequest<I>::handle_open_image(int r) {
198 dout(10) << "r=" << r << dendl;
199
200 if (r < 0) {
201 derr << "failed to open image: " << cpp_strerror(r) << dendl;
202 m_image_ctx->destroy();
203 m_image_ctx = nullptr;
204 finish(r);
205 return;
206 }
207
208 if (m_image_ctx->old_format) {
209 derr << "cannot move v1 image to trash" << dendl;
210 m_ret_val = -EINVAL;
211 close_image();
212 return;
213 }
214
215 acquire_lock();
216 }
217
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();
224 m_ret_val = -EINVAL;
225 close_image();
226 return;
227 }
228
229 dout(10) << dendl;
230
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();
236 }
237
238 template <typename I>
239 void TrashMoveRequest<I>::handle_acquire_lock(int r) {
240 dout(10) << "r=" << r << dendl;
241
242 if (r < 0) {
243 derr << "failed to acquire exclusive lock: " << cpp_strerror(r) << dendl;
244 m_ret_val = r;
245 close_image();
246 return;
247 }
248
249 trash_move();
250 }
251
252 template <typename I>
253 void TrashMoveRequest<I>::trash_move() {
254 dout(10) << dendl;
255
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");
260
261 m_trash_image_spec = {
262 cls::rbd::TRASH_IMAGE_SOURCE_MIRRORING, m_image_ctx->name, delete_time,
263 deferment_end_time};
264
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);
269 req->send();
270 }
271
272 template <typename I>
273 void TrashMoveRequest<I>::handle_trash_move(int r) {
274 dout(10) << "r=" << r << dendl;
275
276 if (r < 0) {
277 derr << "failed to move image to trash: " << cpp_strerror(r) << dendl;
278 m_ret_val = r;
279 close_image();
280 return;
281 }
282
283 m_moved_to_trash = true;
284 remove_mirror_image();
285 }
286
287 template <typename I>
288 void TrashMoveRequest<I>::remove_mirror_image() {
289 dout(10) << dendl;
290
291 librados::ObjectWriteOperation op;
292 librbd::cls_client::mirror_image_remove(&op, m_image_id);
293
294 auto aio_comp = create_rados_callback<
295 TrashMoveRequest<I>,
296 &TrashMoveRequest<I>::handle_remove_mirror_image>(this);
297 int r = m_io_ctx.aio_operate(RBD_MIRRORING, aio_comp, &op);
298 ceph_assert(r == 0);
299 aio_comp->release();
300 }
301
302 template <typename I>
303 void TrashMoveRequest<I>::handle_remove_mirror_image(int r) {
304 dout(10) << "r=" << r << dendl;
305
306 if (r == -ENOENT) {
307 dout(10) << "local image is not mirrored" << dendl;
308 } else if (r < 0) {
309 derr << "failed to remove mirror image state for " << m_global_image_id
310 << ": " << cpp_strerror(r) << dendl;
311 m_ret_val = r;
312 }
313
314 close_image();
315 }
316
317 template <typename I>
318 void TrashMoveRequest<I>::close_image() {
319 dout(10) << dendl;
320
321 Context *ctx = create_context_callback<
322 TrashMoveRequest<I>, &TrashMoveRequest<I>::handle_close_image>(this);
323 m_image_ctx->state->close(ctx);
324 }
325
326 template <typename I>
327 void TrashMoveRequest<I>::handle_close_image(int r) {
328 dout(10) << "r=" << r << dendl;
329
330 m_image_ctx->destroy();
331 m_image_ctx = nullptr;
332
333 if (r < 0) {
334 derr << "failed to close image: " << cpp_strerror(r) << dendl;
335 }
336
337 // don't send notification if we failed
338 if (!m_moved_to_trash) {
339 finish(0);
340 return;
341 }
342
343 notify_trash_add();
344 }
345
346 template <typename I>
347 void TrashMoveRequest<I>::notify_trash_add() {
348 dout(10) << dendl;
349
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);
354 }
355
356 template <typename I>
357 void TrashMoveRequest<I>::handle_notify_trash_add(int r) {
358 dout(10) << "r=" << r << dendl;
359
360 if (r < 0) {
361 derr << "failed to notify trash watchers: " << cpp_strerror(r) << dendl;
362 }
363
364 finish(0);
365 }
366
367 template <typename I>
368 void TrashMoveRequest<I>::finish(int r) {
369 if (m_ret_val < 0) {
370 r = m_ret_val;
371 }
372
373 dout(10) << "r=" << r << dendl;
374
375 m_on_finish->complete(r);
376 delete this;
377 }
378
379 } // namespace image_deleter
380 } // namespace mirror
381 } // namespace rbd
382
383 template class rbd::mirror::image_deleter::TrashMoveRequest<librbd::ImageCtx>;
384