]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/image/RemoveRequest.cc
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / librbd / image / RemoveRequest.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 "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"
17
18 #define dout_subsys ceph_subsys_rbd
19 #undef dout_prefix
20 #define dout_prefix *_dout << "librbd::image::RemoveRequest: " << this << " " \
21 << __func__ << ": "
22
23 namespace librbd {
24 namespace image {
25
26 using librados::IoCtx;
27 using util::create_context_callback;
28 using util::create_async_context_callback;
29 using util::create_rados_callback;
30
31 template<typename I>
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());
42 }
43
44 template<typename I>
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) {
55 }
56
57 template<typename I>
58 void RemoveRequest<I>::send() {
59 ldout(m_cct, 20) << dendl;
60
61 open_image();
62 }
63
64 template<typename I>
65 void RemoveRequest<I>::open_image() {
66 if (m_image_ctx != nullptr) {
67 pre_remove_image();
68 return;
69 }
70
71 m_image_ctx = I::create(m_image_id.empty() ? m_image_name : "", m_image_id,
72 nullptr, m_ioctx, false);
73
74 ldout(m_cct, 20) << dendl;
75
76 using klass = RemoveRequest<I>;
77 Context *ctx = create_context_callback<klass, &klass::handle_open_image>(
78 this);
79
80 m_image_ctx->state->open(OPEN_FLAG_SKIP_OPEN_PARENT, ctx);
81 }
82
83 template<typename I>
84 void RemoveRequest<I>::handle_open_image(int r) {
85 ldout(m_cct, 20) << "r=" << r << dendl;
86
87 if (r < 0) {
88 m_image_ctx->destroy();
89 m_image_ctx = nullptr;
90
91 if (r != -ENOENT) {
92 lderr(m_cct) << "error opening image: " << cpp_strerror(r) << dendl;
93 finish(r);
94 return;
95 }
96
97 remove_image();
98 return;
99 }
100
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;
106
107 pre_remove_image();
108 }
109
110 template<typename I>
111 void RemoveRequest<I>::pre_remove_image() {
112 ldout(m_cct, 5) << dendl;
113
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);
117 req->send();
118 }
119
120 template<typename I>
121 void RemoveRequest<I>::handle_pre_remove_image(int r) {
122 ldout(m_cct, 5) << "r=" << r << dendl;
123
124 if (r < 0) {
125 send_close_image(r);
126 return;
127 }
128
129 trim_image();
130 }
131
132 template<typename I>
133 void RemoveRequest<I>::trim_image() {
134 ldout(m_cct, 20) << dendl;
135
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));
140
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);
144 req->send();
145 }
146
147 template<typename I>
148 void RemoveRequest<I>::handle_trim_image(int r) {
149 ldout(m_cct, 20) << "r=" << r << dendl;
150
151 if (r < 0) {
152 lderr(m_cct) << "failed to remove some object(s): "
153 << cpp_strerror(r) << dendl;
154 send_close_image(r);
155 return;
156 }
157
158 if (m_old_format) {
159 send_close_image(r);
160 return;
161 }
162
163 detach_child();
164 }
165
166 template<typename I>
167 void RemoveRequest<I>::detach_child() {
168 ldout(m_cct, 20) << dendl;
169
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);
173 req->send();
174 }
175
176 template<typename I>
177 void RemoveRequest<I>::handle_detach_child(int r) {
178 ldout(m_cct, 20) << "r=" << r << dendl;
179
180 if (r < 0) {
181 lderr(m_cct) << "failed to detach child from parent: "
182 << cpp_strerror(r) << dendl;
183 send_close_image(r);
184 return;
185 }
186
187 send_disable_mirror();
188 }
189
190 template<typename I>
191 void RemoveRequest<I>::send_disable_mirror() {
192 ldout(m_cct, 20) << dendl;
193
194 using klass = RemoveRequest<I>;
195 Context *ctx = create_context_callback<
196 klass, &klass::handle_disable_mirror>(this);
197
198 mirror::DisableRequest<I> *req =
199 mirror::DisableRequest<I>::create(m_image_ctx, m_force, !m_force, ctx);
200 req->send();
201 }
202
203 template<typename I>
204 void RemoveRequest<I>::handle_disable_mirror(int r) {
205 ldout(m_cct, 20) << "r=" << r << dendl;
206
207 if (r == -EOPNOTSUPP) {
208 r = 0;
209 } else if (r < 0) {
210 lderr(m_cct) << "error disabling image mirroring: "
211 << cpp_strerror(r) << dendl;
212 }
213
214 send_close_image(r);
215 }
216
217 template<typename I>
218 void RemoveRequest<I>::send_close_image(int r) {
219 ldout(m_cct, 20) << dendl;
220
221 m_ret_val = r;
222 using klass = RemoveRequest<I>;
223 Context *ctx = create_context_callback<
224 klass, &klass::handle_send_close_image>(this);
225
226 m_image_ctx->state->close(ctx);
227 }
228
229 template<typename I>
230 void RemoveRequest<I>::handle_send_close_image(int r) {
231 ldout(m_cct, 20) << "r=" << r << dendl;
232
233 if (r < 0) {
234 lderr(m_cct) << "error encountered while closing image: "
235 << cpp_strerror(r) << dendl;
236 }
237
238 m_image_ctx->destroy();
239 m_image_ctx = nullptr;
240 if (m_ret_val < 0) {
241 r = m_ret_val;
242 finish(r);
243 return;
244 }
245
246 remove_header();
247 }
248
249 template<typename I>
250 void RemoveRequest<I>::remove_header() {
251 ldout(m_cct, 20) << dendl;
252
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);
257 ceph_assert(r == 0);
258 rados_completion->release();
259 }
260
261 template<typename I>
262 void RemoveRequest<I>::handle_remove_header(int r) {
263 ldout(m_cct, 20) << "r=" << r << dendl;
264
265 if (r < 0 && r != -ENOENT) {
266 lderr(m_cct) << "error removing header: " << cpp_strerror(r) << dendl;
267 m_ret_val = r;
268 }
269
270 remove_image();
271 }
272
273 template<typename I>
274 void RemoveRequest<I>::remove_header_v2() {
275 ldout(m_cct, 20) << dendl;
276
277 if (m_header_oid.empty()) {
278 m_header_oid = util::header_name(m_image_id);
279 }
280
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);
285 ceph_assert(r == 0);
286 rados_completion->release();
287 }
288
289 template<typename I>
290 void RemoveRequest<I>::handle_remove_header_v2(int r) {
291 ldout(m_cct, 20) << "r=" << r << dendl;
292
293 if (r < 0 && r != -ENOENT) {
294 lderr(m_cct) << "error removing header: " << cpp_strerror(r) << dendl;
295 finish(r);
296 return;
297 }
298
299 send_journal_remove();
300 }
301
302 template<typename I>
303 void RemoveRequest<I>::send_journal_remove() {
304 ldout(m_cct, 20) << dendl;
305
306 using klass = RemoveRequest<I>;
307 Context *ctx = create_context_callback<
308 klass, &klass::handle_journal_remove>(this);
309
310 journal::RemoveRequest<I> *req = journal::RemoveRequest<I>::create(
311 m_ioctx, m_image_id, Journal<>::IMAGE_CLIENT_ID, m_op_work_queue, ctx);
312 req->send();
313 }
314
315 template<typename I>
316 void RemoveRequest<I>::handle_journal_remove(int r) {
317 ldout(m_cct, 20) << "r=" << r << dendl;
318
319 if (r < 0 && r != -ENOENT) {
320 lderr(m_cct) << "failed to remove image journal: " << cpp_strerror(r)
321 << dendl;
322 finish(r);
323 return;
324 } else {
325 r = 0;
326 }
327
328 send_object_map_remove();
329 }
330
331 template<typename I>
332 void RemoveRequest<I>::send_object_map_remove() {
333 ldout(m_cct, 20) << dendl;
334
335 using klass = RemoveRequest<I>;
336 librados::AioCompletion *rados_completion =
337 create_rados_callback<klass, &klass::handle_object_map_remove>(this);
338
339 int r = ObjectMap<>::aio_remove(m_ioctx,
340 m_image_id,
341 rados_completion);
342 ceph_assert(r == 0);
343 rados_completion->release();
344 }
345
346 template<typename I>
347 void RemoveRequest<I>::handle_object_map_remove(int r) {
348 ldout(m_cct, 20) << "r=" << r << dendl;
349
350 if (r < 0 && r != -ENOENT) {
351 lderr(m_cct) << "failed to remove image journal: " << cpp_strerror(r)
352 << dendl;
353 finish(r);
354 return;
355 } else {
356 r = 0;
357 }
358
359 mirror_image_remove();
360 }
361
362 template<typename I>
363 void RemoveRequest<I>::mirror_image_remove() {
364 ldout(m_cct, 20) << dendl;
365
366 librados::ObjectWriteOperation op;
367 cls_client::mirror_image_remove(&op, m_image_id);
368
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);
373 ceph_assert(r == 0);
374 rados_completion->release();
375 }
376
377 template<typename I>
378 void RemoveRequest<I>::handle_mirror_image_remove(int r) {
379 ldout(m_cct, 20) << "r=" << r << dendl;
380
381 if (r < 0 && r != -ENOENT && r != -EOPNOTSUPP) {
382 lderr(m_cct) << "failed to remove mirror image state: "
383 << cpp_strerror(r) << dendl;
384 finish(r);
385 return;
386 }
387
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.
391 finish(0);
392 return;
393 }
394
395 remove_id_object();
396 }
397
398 template<typename I>
399 void RemoveRequest<I>::remove_image() {
400 ldout(m_cct, 20) << dendl;
401
402 if (m_old_format || m_unknown_format) {
403 remove_v1_image();
404 } else {
405 remove_v2_image();
406 }
407 }
408
409 template<typename I>
410 void RemoveRequest<I>::remove_v1_image() {
411 ldout(m_cct, 20) << dendl;
412
413 Context *ctx = new FunctionContext([this] (int r) {
414 r = tmap_rm(m_ioctx, m_image_name);
415 handle_remove_v1_image(r);
416 });
417
418 m_op_work_queue->queue(ctx, 0);
419 }
420
421 template<typename I>
422 void RemoveRequest<I>::handle_remove_v1_image(int r) {
423 ldout(m_cct, 20) << "r=" << r << dendl;
424
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;
430 }
431
432 m_on_finish->complete(r);
433 delete this;
434 return;
435 }
436
437 if (!m_old_format) {
438 remove_v2_image();
439 }
440 }
441
442 template<typename I>
443 void RemoveRequest<I>::remove_v2_image() {
444 ldout(m_cct, 20) << dendl;
445
446 if (m_image_id.empty()) {
447 dir_get_image_id();
448 return;
449 } else if (m_image_name.empty()) {
450 dir_get_image_name();
451 return;
452 }
453
454 remove_header_v2();
455 return;
456 }
457
458 template<typename I>
459 void RemoveRequest<I>::dir_get_image_id() {
460 ldout(m_cct, 20) << dendl;
461
462 librados::ObjectReadOperation op;
463 librbd::cls_client::dir_get_id_start(&op, m_image_name);
464
465 using klass = RemoveRequest<I>;
466 librados::AioCompletion *rados_completion =
467 create_rados_callback<klass, &klass::handle_dir_get_image_id>(this);
468 m_out_bl.clear();
469 int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op, &m_out_bl);
470 ceph_assert(r == 0);
471 rados_completion->release();
472 }
473
474 template<typename I>
475 void RemoveRequest<I>::handle_dir_get_image_id(int r) {
476 ldout(m_cct, 20) << "r=" << r << dendl;
477
478 if (r < 0 && r != -ENOENT) {
479 lderr(m_cct) << "error fetching image id: " << cpp_strerror(r)
480 << dendl;
481 finish(r);
482 return;
483 }
484
485 if (r == 0) {
486 auto iter = m_out_bl.cbegin();
487 r = librbd::cls_client::dir_get_id_finish(&iter, &m_image_id);
488 if (r < 0) {
489 finish(r);
490 return;
491 }
492 }
493
494 remove_header_v2();
495 }
496
497 template<typename I>
498 void RemoveRequest<I>::dir_get_image_name() {
499 ldout(m_cct, 20) << dendl;
500
501 librados::ObjectReadOperation op;
502 librbd::cls_client::dir_get_name_start(&op, m_image_id);
503
504 using klass = RemoveRequest<I>;
505 librados::AioCompletion *rados_completion =
506 create_rados_callback<klass, &klass::handle_dir_get_image_name>(this);
507 m_out_bl.clear();
508 int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op, &m_out_bl);
509 ceph_assert(r == 0);
510 rados_completion->release();
511 }
512
513 template<typename I>
514 void RemoveRequest<I>::handle_dir_get_image_name(int r) {
515 ldout(m_cct, 20) << "r=" << r << dendl;
516
517 if (r < 0 && r != -ENOENT) {
518 lderr(m_cct) << "error fetching image name: " << cpp_strerror(r)
519 << dendl;
520 finish(r);
521 return;
522 }
523
524 if (r == 0) {
525 auto iter = m_out_bl.cbegin();
526 r = librbd::cls_client::dir_get_name_finish(&iter, &m_image_name);
527 if (r < 0) {
528 finish(r);
529 return;
530 }
531 }
532
533 remove_header_v2();
534 }
535
536 template<typename I>
537 void RemoveRequest<I>::remove_id_object() {
538 ldout(m_cct, 20) << dendl;
539
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);
544 ceph_assert(r == 0);
545 rados_completion->release();
546 }
547
548 template<typename I>
549 void RemoveRequest<I>::handle_remove_id_object(int r) {
550 ldout(m_cct, 20) << "r=" << r << dendl;
551
552 if (r < 0 && r != -ENOENT) {
553 lderr(m_cct) << "error removing id object: " << cpp_strerror(r)
554 << dendl;
555 finish(r);
556 return;
557 }
558
559 dir_remove_image();
560 }
561
562 template<typename I>
563 void RemoveRequest<I>::dir_remove_image() {
564 ldout(m_cct, 20) << dendl;
565
566 librados::ObjectWriteOperation op;
567 librbd::cls_client::dir_remove_image(&op, m_image_name, m_image_id);
568
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);
573 ceph_assert(r == 0);
574 rados_completion->release();
575 }
576
577 template<typename I>
578 void RemoveRequest<I>::handle_dir_remove_image(int r) {
579 ldout(m_cct, 20) << "r=" << r << dendl;
580
581 if (r < 0 && r != -ENOENT) {
582 lderr(m_cct) << "error removing image from v2 directory: "
583 << cpp_strerror(r) << dendl;
584 }
585
586 finish(r);
587 }
588
589 template<typename I>
590 void RemoveRequest<I>::finish(int r) {
591 ldout(m_cct, 20) << "r=" << r << dendl;
592
593 m_on_finish->complete(r);
594 delete this;
595 }
596
597 } // namespace image
598 } // namespace librbd
599
600 template class librbd::image::RemoveRequest<librbd::ImageCtx>;