]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/image/RemoveRequest.cc
import ceph 14.2.5
[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 if (!m_image_ctx->data_ctx.is_valid()) {
130 detach_child();
131 return;
132 }
133
134 trim_image();
135 }
136
137 template<typename I>
138 void RemoveRequest<I>::trim_image() {
139 ldout(m_cct, 20) << dendl;
140
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));
145
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);
149 req->send();
150 }
151
152 template<typename I>
153 void RemoveRequest<I>::handle_trim_image(int r) {
154 ldout(m_cct, 20) << "r=" << r << dendl;
155
156 if (r < 0) {
157 lderr(m_cct) << "failed to remove some object(s): "
158 << cpp_strerror(r) << dendl;
159 send_close_image(r);
160 return;
161 }
162
163 if (m_old_format) {
164 send_close_image(r);
165 return;
166 }
167
168 detach_child();
169 }
170
171 template<typename I>
172 void RemoveRequest<I>::detach_child() {
173 ldout(m_cct, 20) << dendl;
174
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);
178 req->send();
179 }
180
181 template<typename I>
182 void RemoveRequest<I>::handle_detach_child(int r) {
183 ldout(m_cct, 20) << "r=" << r << dendl;
184
185 if (r < 0) {
186 lderr(m_cct) << "failed to detach child from parent: "
187 << cpp_strerror(r) << dendl;
188 send_close_image(r);
189 return;
190 }
191
192 send_disable_mirror();
193 }
194
195 template<typename I>
196 void RemoveRequest<I>::send_disable_mirror() {
197 ldout(m_cct, 20) << dendl;
198
199 using klass = RemoveRequest<I>;
200 Context *ctx = create_context_callback<
201 klass, &klass::handle_disable_mirror>(this);
202
203 mirror::DisableRequest<I> *req =
204 mirror::DisableRequest<I>::create(m_image_ctx, m_force, !m_force, ctx);
205 req->send();
206 }
207
208 template<typename I>
209 void RemoveRequest<I>::handle_disable_mirror(int r) {
210 ldout(m_cct, 20) << "r=" << r << dendl;
211
212 if (r == -EOPNOTSUPP) {
213 r = 0;
214 } else if (r < 0) {
215 lderr(m_cct) << "error disabling image mirroring: "
216 << cpp_strerror(r) << dendl;
217 }
218
219 send_close_image(r);
220 }
221
222 template<typename I>
223 void RemoveRequest<I>::send_close_image(int r) {
224 ldout(m_cct, 20) << dendl;
225
226 m_ret_val = r;
227 using klass = RemoveRequest<I>;
228 Context *ctx = create_context_callback<
229 klass, &klass::handle_send_close_image>(this);
230
231 m_image_ctx->state->close(ctx);
232 }
233
234 template<typename I>
235 void RemoveRequest<I>::handle_send_close_image(int r) {
236 ldout(m_cct, 20) << "r=" << r << dendl;
237
238 if (r < 0) {
239 lderr(m_cct) << "error encountered while closing image: "
240 << cpp_strerror(r) << dendl;
241 }
242
243 m_image_ctx->destroy();
244 m_image_ctx = nullptr;
245 if (m_ret_val < 0) {
246 r = m_ret_val;
247 finish(r);
248 return;
249 }
250
251 remove_header();
252 }
253
254 template<typename I>
255 void RemoveRequest<I>::remove_header() {
256 ldout(m_cct, 20) << dendl;
257
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);
262 ceph_assert(r == 0);
263 rados_completion->release();
264 }
265
266 template<typename I>
267 void RemoveRequest<I>::handle_remove_header(int r) {
268 ldout(m_cct, 20) << "r=" << r << dendl;
269
270 if (r < 0 && r != -ENOENT) {
271 lderr(m_cct) << "error removing header: " << cpp_strerror(r) << dendl;
272 m_ret_val = r;
273 }
274
275 remove_image();
276 }
277
278 template<typename I>
279 void RemoveRequest<I>::remove_header_v2() {
280 ldout(m_cct, 20) << dendl;
281
282 if (m_header_oid.empty()) {
283 m_header_oid = util::header_name(m_image_id);
284 }
285
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);
290 ceph_assert(r == 0);
291 rados_completion->release();
292 }
293
294 template<typename I>
295 void RemoveRequest<I>::handle_remove_header_v2(int r) {
296 ldout(m_cct, 20) << "r=" << r << dendl;
297
298 if (r < 0 && r != -ENOENT) {
299 lderr(m_cct) << "error removing header: " << cpp_strerror(r) << dendl;
300 finish(r);
301 return;
302 }
303
304 send_journal_remove();
305 }
306
307 template<typename I>
308 void RemoveRequest<I>::send_journal_remove() {
309 ldout(m_cct, 20) << dendl;
310
311 using klass = RemoveRequest<I>;
312 Context *ctx = create_context_callback<
313 klass, &klass::handle_journal_remove>(this);
314
315 journal::RemoveRequest<I> *req = journal::RemoveRequest<I>::create(
316 m_ioctx, m_image_id, Journal<>::IMAGE_CLIENT_ID, m_op_work_queue, ctx);
317 req->send();
318 }
319
320 template<typename I>
321 void RemoveRequest<I>::handle_journal_remove(int r) {
322 ldout(m_cct, 20) << "r=" << r << dendl;
323
324 if (r < 0 && r != -ENOENT) {
325 lderr(m_cct) << "failed to remove image journal: " << cpp_strerror(r)
326 << dendl;
327 finish(r);
328 return;
329 } else {
330 r = 0;
331 }
332
333 send_object_map_remove();
334 }
335
336 template<typename I>
337 void RemoveRequest<I>::send_object_map_remove() {
338 ldout(m_cct, 20) << dendl;
339
340 using klass = RemoveRequest<I>;
341 librados::AioCompletion *rados_completion =
342 create_rados_callback<klass, &klass::handle_object_map_remove>(this);
343
344 int r = ObjectMap<>::aio_remove(m_ioctx,
345 m_image_id,
346 rados_completion);
347 ceph_assert(r == 0);
348 rados_completion->release();
349 }
350
351 template<typename I>
352 void RemoveRequest<I>::handle_object_map_remove(int r) {
353 ldout(m_cct, 20) << "r=" << r << dendl;
354
355 if (r < 0 && r != -ENOENT) {
356 lderr(m_cct) << "failed to remove image journal: " << cpp_strerror(r)
357 << dendl;
358 finish(r);
359 return;
360 } else {
361 r = 0;
362 }
363
364 mirror_image_remove();
365 }
366
367 template<typename I>
368 void RemoveRequest<I>::mirror_image_remove() {
369 ldout(m_cct, 20) << dendl;
370
371 librados::ObjectWriteOperation op;
372 cls_client::mirror_image_remove(&op, m_image_id);
373
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);
378 ceph_assert(r == 0);
379 rados_completion->release();
380 }
381
382 template<typename I>
383 void RemoveRequest<I>::handle_mirror_image_remove(int r) {
384 ldout(m_cct, 20) << "r=" << r << dendl;
385
386 if (r < 0 && r != -ENOENT && r != -EOPNOTSUPP) {
387 lderr(m_cct) << "failed to remove mirror image state: "
388 << cpp_strerror(r) << dendl;
389 finish(r);
390 return;
391 }
392
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.
396 finish(0);
397 return;
398 }
399
400 remove_id_object();
401 }
402
403 template<typename I>
404 void RemoveRequest<I>::remove_image() {
405 ldout(m_cct, 20) << dendl;
406
407 if (m_old_format || m_unknown_format) {
408 remove_v1_image();
409 } else {
410 remove_v2_image();
411 }
412 }
413
414 template<typename I>
415 void RemoveRequest<I>::remove_v1_image() {
416 ldout(m_cct, 20) << dendl;
417
418 Context *ctx = new FunctionContext([this] (int r) {
419 r = tmap_rm(m_ioctx, m_image_name);
420 handle_remove_v1_image(r);
421 });
422
423 m_op_work_queue->queue(ctx, 0);
424 }
425
426 template<typename I>
427 void RemoveRequest<I>::handle_remove_v1_image(int r) {
428 ldout(m_cct, 20) << "r=" << r << dendl;
429
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;
435 }
436
437 m_on_finish->complete(r);
438 delete this;
439 return;
440 }
441
442 if (!m_old_format) {
443 remove_v2_image();
444 }
445 }
446
447 template<typename I>
448 void RemoveRequest<I>::remove_v2_image() {
449 ldout(m_cct, 20) << dendl;
450
451 if (m_image_id.empty()) {
452 dir_get_image_id();
453 return;
454 } else if (m_image_name.empty()) {
455 dir_get_image_name();
456 return;
457 }
458
459 remove_header_v2();
460 return;
461 }
462
463 template<typename I>
464 void RemoveRequest<I>::dir_get_image_id() {
465 ldout(m_cct, 20) << dendl;
466
467 librados::ObjectReadOperation op;
468 librbd::cls_client::dir_get_id_start(&op, m_image_name);
469
470 using klass = RemoveRequest<I>;
471 librados::AioCompletion *rados_completion =
472 create_rados_callback<klass, &klass::handle_dir_get_image_id>(this);
473 m_out_bl.clear();
474 int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op, &m_out_bl);
475 ceph_assert(r == 0);
476 rados_completion->release();
477 }
478
479 template<typename I>
480 void RemoveRequest<I>::handle_dir_get_image_id(int r) {
481 ldout(m_cct, 20) << "r=" << r << dendl;
482
483 if (r < 0 && r != -ENOENT) {
484 lderr(m_cct) << "error fetching image id: " << cpp_strerror(r)
485 << dendl;
486 finish(r);
487 return;
488 }
489
490 if (r == 0) {
491 auto iter = m_out_bl.cbegin();
492 r = librbd::cls_client::dir_get_id_finish(&iter, &m_image_id);
493 if (r < 0) {
494 finish(r);
495 return;
496 }
497 }
498
499 remove_header_v2();
500 }
501
502 template<typename I>
503 void RemoveRequest<I>::dir_get_image_name() {
504 ldout(m_cct, 20) << dendl;
505
506 librados::ObjectReadOperation op;
507 librbd::cls_client::dir_get_name_start(&op, m_image_id);
508
509 using klass = RemoveRequest<I>;
510 librados::AioCompletion *rados_completion =
511 create_rados_callback<klass, &klass::handle_dir_get_image_name>(this);
512 m_out_bl.clear();
513 int r = m_ioctx.aio_operate(RBD_DIRECTORY, rados_completion, &op, &m_out_bl);
514 ceph_assert(r == 0);
515 rados_completion->release();
516 }
517
518 template<typename I>
519 void RemoveRequest<I>::handle_dir_get_image_name(int r) {
520 ldout(m_cct, 20) << "r=" << r << dendl;
521
522 if (r < 0 && r != -ENOENT) {
523 lderr(m_cct) << "error fetching image name: " << cpp_strerror(r)
524 << dendl;
525 finish(r);
526 return;
527 }
528
529 if (r == 0) {
530 auto iter = m_out_bl.cbegin();
531 r = librbd::cls_client::dir_get_name_finish(&iter, &m_image_name);
532 if (r < 0) {
533 finish(r);
534 return;
535 }
536 }
537
538 remove_header_v2();
539 }
540
541 template<typename I>
542 void RemoveRequest<I>::remove_id_object() {
543 ldout(m_cct, 20) << dendl;
544
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);
549 ceph_assert(r == 0);
550 rados_completion->release();
551 }
552
553 template<typename I>
554 void RemoveRequest<I>::handle_remove_id_object(int r) {
555 ldout(m_cct, 20) << "r=" << r << dendl;
556
557 if (r < 0 && r != -ENOENT) {
558 lderr(m_cct) << "error removing id object: " << cpp_strerror(r)
559 << dendl;
560 finish(r);
561 return;
562 }
563
564 dir_remove_image();
565 }
566
567 template<typename I>
568 void RemoveRequest<I>::dir_remove_image() {
569 ldout(m_cct, 20) << dendl;
570
571 librados::ObjectWriteOperation op;
572 librbd::cls_client::dir_remove_image(&op, m_image_name, m_image_id);
573
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);
578 ceph_assert(r == 0);
579 rados_completion->release();
580 }
581
582 template<typename I>
583 void RemoveRequest<I>::handle_dir_remove_image(int r) {
584 ldout(m_cct, 20) << "r=" << r << dendl;
585
586 if (r < 0 && r != -ENOENT) {
587 lderr(m_cct) << "error removing image from v2 directory: "
588 << cpp_strerror(r) << dendl;
589 }
590
591 finish(r);
592 }
593
594 template<typename I>
595 void RemoveRequest<I>::finish(int r) {
596 ldout(m_cct, 20) << "r=" << r << dendl;
597
598 m_on_finish->complete(r);
599 delete this;
600 }
601
602 } // namespace image
603 } // namespace librbd
604
605 template class librbd::image::RemoveRequest<librbd::ImageCtx>;