]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/operation/DisableFeaturesRequest.cc
update sources to 12.2.10
[ceph.git] / ceph / src / librbd / operation / DisableFeaturesRequest.cc
CommitLineData
7c673cae
FG
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/operation/DisableFeaturesRequest.h"
5#include "common/dout.h"
6#include "common/errno.h"
7#include "cls/rbd/cls_rbd_client.h"
8#include "librbd/ExclusiveLock.h"
9#include "librbd/ImageCtx.h"
10#include "librbd/ImageState.h"
11#include "librbd/Journal.h"
12#include "librbd/Utils.h"
13#include "librbd/image/SetFlagsRequest.h"
14#include "librbd/io/ImageRequestWQ.h"
15#include "librbd/journal/RemoveRequest.h"
16#include "librbd/mirror/DisableRequest.h"
17#include "librbd/object_map/RemoveRequest.h"
18
19#define dout_subsys ceph_subsys_rbd
20#undef dout_prefix
21#define dout_prefix *_dout << "librbd::DisableFeaturesRequest: "
22
23namespace librbd {
24namespace operation {
25
26using util::create_async_context_callback;
27using util::create_context_callback;
28using util::create_rados_callback;
29
30template <typename I>
31DisableFeaturesRequest<I>::DisableFeaturesRequest(I &image_ctx,
32 Context *on_finish,
33 uint64_t journal_op_tid,
34 uint64_t features,
35 bool force)
36 : Request<I>(image_ctx, on_finish, journal_op_tid), m_features(features),
37 m_force(force) {
38}
39
40template <typename I>
41void DisableFeaturesRequest<I>::send_op() {
42 I &image_ctx = this->m_image_ctx;
43 CephContext *cct = image_ctx.cct;
44 assert(image_ctx.owner_lock.is_locked());
45
46 ldout(cct, 20) << this << " " << __func__ << ": features=" << m_features
47 << dendl;
48
49 send_prepare_lock();
50}
51
52template <typename I>
53bool DisableFeaturesRequest<I>::should_complete(int r) {
54 I &image_ctx = this->m_image_ctx;
55 CephContext *cct = image_ctx.cct;
56 ldout(cct, 20) << this << " " << __func__ << "r=" << r << dendl;
57
58 if (r < 0) {
59 lderr(cct) << "encountered error: " << cpp_strerror(r) << dendl;
60 }
61 return true;
62}
63
64template <typename I>
65void DisableFeaturesRequest<I>::send_prepare_lock() {
66 I &image_ctx = this->m_image_ctx;
67 CephContext *cct = image_ctx.cct;
68 ldout(cct, 20) << this << " " << __func__ << dendl;
69
70 image_ctx.state->prepare_lock(create_async_context_callback(
71 image_ctx, create_context_callback<
72 DisableFeaturesRequest<I>,
73 &DisableFeaturesRequest<I>::handle_prepare_lock>(this)));
74}
75
76template <typename I>
77Context *DisableFeaturesRequest<I>::handle_prepare_lock(int *result) {
78 I &image_ctx = this->m_image_ctx;
79 CephContext *cct = image_ctx.cct;
80 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
81
82 if (*result < 0) {
83 lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl;
84 return this->create_context_finisher(*result);
85 }
86
87 send_block_writes();
88 return nullptr;
89}
90
91template <typename I>
92void DisableFeaturesRequest<I>::send_block_writes() {
93 I &image_ctx = this->m_image_ctx;
94 CephContext *cct = image_ctx.cct;
95 ldout(cct, 20) << this << " " << __func__ << dendl;
96
97 RWLock::WLocker locker(image_ctx.owner_lock);
98 image_ctx.io_work_queue->block_writes(create_context_callback<
99 DisableFeaturesRequest<I>,
100 &DisableFeaturesRequest<I>::handle_block_writes>(this));
101}
102
103template <typename I>
104Context *DisableFeaturesRequest<I>::handle_block_writes(int *result) {
105 I &image_ctx = this->m_image_ctx;
106 CephContext *cct = image_ctx.cct;
107 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
108
109 if (*result < 0) {
110 lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl;
111 return handle_finish(*result);
112 }
113 m_writes_blocked = true;
114
115 {
116 RWLock::WLocker locker(image_ctx.owner_lock);
117 // avoid accepting new requests from peers while we manipulate
118 // the image features
119 if (image_ctx.exclusive_lock != nullptr &&
120 (image_ctx.journal == nullptr ||
121 !image_ctx.journal->is_journal_replaying())) {
122 image_ctx.exclusive_lock->block_requests(0);
123 m_requests_blocked = true;
124 }
125 }
126
127 send_acquire_exclusive_lock();
128 return nullptr;
129}
130
131template <typename I>
132void DisableFeaturesRequest<I>::send_acquire_exclusive_lock() {
133 I &image_ctx = this->m_image_ctx;
134 CephContext *cct = image_ctx.cct;
135 ldout(cct, 20) << this << " " << __func__ << dendl;
136
137 Context *ctx = create_context_callback<
138 DisableFeaturesRequest<I>,
139 &DisableFeaturesRequest<I>::handle_acquire_exclusive_lock>(this);
140
141 {
142 RWLock::WLocker locker(image_ctx.owner_lock);
143 // if disabling features w/ exclusive lock supported, we need to
144 // acquire the lock to temporarily block IO against the image
145 if (image_ctx.exclusive_lock != nullptr &&
146 !image_ctx.exclusive_lock->is_lock_owner()) {
147 m_acquired_lock = true;
148
149 image_ctx.exclusive_lock->acquire_lock(ctx);
150 return;
151 }
152 }
153
154 ctx->complete(0);
155}
156
157template <typename I>
158Context *DisableFeaturesRequest<I>::handle_acquire_exclusive_lock(int *result) {
159 I &image_ctx = this->m_image_ctx;
160 CephContext *cct = image_ctx.cct;
161 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
162
91327a77 163 image_ctx.owner_lock.get_read();
7c673cae
FG
164 if (*result < 0) {
165 lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl;
91327a77 166 image_ctx.owner_lock.put_read();
7c673cae 167 return handle_finish(*result);
91327a77
AA
168 } else if (image_ctx.exclusive_lock != nullptr &&
169 !image_ctx.exclusive_lock->is_lock_owner()) {
7c673cae 170 lderr(cct) << "failed to acquire exclusive lock" << dendl;
91327a77
AA
171 *result = image_ctx.exclusive_lock->get_unlocked_op_error();
172 image_ctx.owner_lock.put_read();
7c673cae
FG
173 return handle_finish(*result);
174 }
175
176 do {
7c673cae
FG
177 m_features &= image_ctx.features;
178 m_new_features = image_ctx.features & ~m_features;
179 m_features_mask = m_features;
180
181 if ((m_features & RBD_FEATURE_EXCLUSIVE_LOCK) != 0) {
182 if ((m_new_features & RBD_FEATURE_OBJECT_MAP) != 0 ||
183 (m_new_features & RBD_FEATURE_JOURNALING) != 0) {
184 lderr(cct) << "cannot disable exclusive-lock. object-map "
185 "or journaling must be disabled before "
186 "disabling exclusive-lock." << dendl;
187 *result = -EINVAL;
188 break;
189 }
190 m_features_mask |= (RBD_FEATURE_OBJECT_MAP |
191 RBD_FEATURE_JOURNALING);
192 }
193 if ((m_features & RBD_FEATURE_FAST_DIFF) != 0) {
194 m_disable_flags |= RBD_FLAG_FAST_DIFF_INVALID;
195 }
196 if ((m_features & RBD_FEATURE_OBJECT_MAP) != 0) {
197 if ((m_new_features & RBD_FEATURE_FAST_DIFF) != 0) {
198 lderr(cct) << "cannot disable object-map. fast-diff must be "
199 "disabled before disabling object-map." << dendl;
200 *result = -EINVAL;
201 break;
202 }
203 m_disable_flags |= RBD_FLAG_OBJECT_MAP_INVALID;
204 }
205 } while (false);
91327a77 206 image_ctx.owner_lock.put_read();
7c673cae
FG
207
208 if (*result < 0) {
209 return handle_finish(*result);
210 }
211
212 send_get_mirror_mode();
213 return nullptr;
214}
215
216template <typename I>
217void DisableFeaturesRequest<I>::send_get_mirror_mode() {
218 I &image_ctx = this->m_image_ctx;
219 CephContext *cct = image_ctx.cct;
220
221 if ((m_features & RBD_FEATURE_JOURNALING) == 0) {
222 send_append_op_event();
223 return;
224 }
225
226 ldout(cct, 20) << this << " " << __func__ << dendl;
227
228 librados::ObjectReadOperation op;
229 cls_client::mirror_mode_get_start(&op);
230
231 using klass = DisableFeaturesRequest<I>;
232 librados::AioCompletion *comp =
233 create_rados_callback<klass, &klass::handle_get_mirror_mode>(this);
234 m_out_bl.clear();
235 int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
236 assert(r == 0);
237 comp->release();
238}
239
240template <typename I>
241Context *DisableFeaturesRequest<I>::handle_get_mirror_mode(int *result) {
242 I &image_ctx = this->m_image_ctx;
243 CephContext *cct = image_ctx.cct;
244 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
245
246 if (*result == 0) {
247 bufferlist::iterator it = m_out_bl.begin();
248 *result = cls_client::mirror_mode_get_finish(&it, &m_mirror_mode);
249 }
250
251 if (*result < 0 && *result != -ENOENT) {
252 lderr(cct) << "failed to retrieve pool mirror mode: "
253 << cpp_strerror(*result) << dendl;
254 return handle_finish(*result);
255 }
256
257 ldout(cct, 20) << this << " " << __func__ << ": m_mirror_mode="
258 << m_mirror_mode << dendl;
259
260 send_get_mirror_image();
261 return nullptr;
262}
263
264template <typename I>
265void DisableFeaturesRequest<I>::send_get_mirror_image() {
266 I &image_ctx = this->m_image_ctx;
267 CephContext *cct = image_ctx.cct;
268
269 if (m_mirror_mode != cls::rbd::MIRROR_MODE_IMAGE) {
270 send_disable_mirror_image();
271 return;
272 }
273
274 ldout(cct, 20) << this << " " << __func__ << dendl;
275
276 librados::ObjectReadOperation op;
277 cls_client::mirror_image_get_start(&op, image_ctx.id);
278
279 using klass = DisableFeaturesRequest<I>;
280 librados::AioCompletion *comp =
281 create_rados_callback<klass, &klass::handle_get_mirror_image>(this);
282 m_out_bl.clear();
283 int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
284 assert(r == 0);
285 comp->release();
286}
287
288template <typename I>
289Context *DisableFeaturesRequest<I>::handle_get_mirror_image(int *result) {
290 I &image_ctx = this->m_image_ctx;
291 CephContext *cct = image_ctx.cct;
292 ldout(cct, 20) << this << " " << __func__ << dendl;
293
294 cls::rbd::MirrorImage mirror_image;
295
296 if (*result == 0) {
297 bufferlist::iterator it = m_out_bl.begin();
298 *result = cls_client::mirror_image_get_finish(&it, &mirror_image);
299 }
300
301 if (*result < 0 && *result != -ENOENT) {
302 lderr(cct) << "failed to retrieve pool mirror image: "
303 << cpp_strerror(*result) << dendl;
304 return handle_finish(*result);
305 }
306
307 if ((mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) && !m_force) {
308 lderr(cct) << "cannot disable journaling: image mirroring "
309 << "enabled and mirror pool mode set to image"
310 << dendl;
311 *result = -EINVAL;
312 return handle_finish(*result);
313 }
314
315 send_disable_mirror_image();
316 return nullptr;
317}
318
319template <typename I>
320void DisableFeaturesRequest<I>::send_disable_mirror_image() {
321 I &image_ctx = this->m_image_ctx;
322 CephContext *cct = image_ctx.cct;
323
324 ldout(cct, 20) << this << " " << __func__ << dendl;
325
326 Context *ctx = create_context_callback<
327 DisableFeaturesRequest<I>,
328 &DisableFeaturesRequest<I>::handle_disable_mirror_image>(this);
329
330 mirror::DisableRequest<I> *req =
331 mirror::DisableRequest<I>::create(&image_ctx, m_force, true, ctx);
332 req->send();
333}
334
335template <typename I>
336Context *DisableFeaturesRequest<I>::handle_disable_mirror_image(int *result) {
337 I &image_ctx = this->m_image_ctx;
338 CephContext *cct = image_ctx.cct;
339 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
340
341 if (*result < 0) {
342 lderr(cct) << "failed to disable image mirroring: " << cpp_strerror(*result)
343 << dendl;
344 // not fatal
345 }
346
347 send_close_journal();
348 return nullptr;
349}
350
351template <typename I>
352void DisableFeaturesRequest<I>::send_close_journal() {
353 I &image_ctx = this->m_image_ctx;
354 CephContext *cct = image_ctx.cct;
355
356 {
357 RWLock::WLocker locker(image_ctx.owner_lock);
358 if (image_ctx.journal != nullptr) {
7c673cae
FG
359 ldout(cct, 20) << this << " " << __func__ << dendl;
360
224ce89b 361 std::swap(m_journal, image_ctx.journal);
7c673cae
FG
362 Context *ctx = create_context_callback<
363 DisableFeaturesRequest<I>,
364 &DisableFeaturesRequest<I>::handle_close_journal>(this);
365
224ce89b 366 m_journal->close(ctx);
7c673cae
FG
367 return;
368 }
369 }
370
371 send_remove_journal();
372}
373
374template <typename I>
375Context *DisableFeaturesRequest<I>::handle_close_journal(int *result) {
376 I &image_ctx = this->m_image_ctx;
377 CephContext *cct = image_ctx.cct;
378 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
379
380 if (*result < 0) {
381 lderr(cct) << "failed to close image journal: " << cpp_strerror(*result)
382 << dendl;
7c673cae
FG
383 }
384
224ce89b
WB
385 assert(m_journal != nullptr);
386 delete m_journal;
387 m_journal = nullptr;
388
7c673cae
FG
389 send_remove_journal();
390 return nullptr;
391}
392
393template <typename I>
394void DisableFeaturesRequest<I>::send_remove_journal() {
395 I &image_ctx = this->m_image_ctx;
396 CephContext *cct = image_ctx.cct;
397 ldout(cct, 20) << this << " " << __func__ << dendl;
398
399 Context *ctx = create_context_callback<
400 DisableFeaturesRequest<I>,
401 &DisableFeaturesRequest<I>::handle_remove_journal>(this);
402
403 journal::RemoveRequest<I> *req = journal::RemoveRequest<I>::create(
404 image_ctx.md_ctx, image_ctx.id, librbd::Journal<>::IMAGE_CLIENT_ID,
405 image_ctx.op_work_queue, ctx);
406
407 req->send();
408}
409
410template <typename I>
411Context *DisableFeaturesRequest<I>::handle_remove_journal(int *result) {
412 I &image_ctx = this->m_image_ctx;
413 CephContext *cct = image_ctx.cct;
414 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
415
416 if (*result < 0) {
417 lderr(cct) << "failed to remove image journal: " << cpp_strerror(*result)
418 << dendl;
419 return handle_finish(*result);
420 }
421
422 send_append_op_event();
423 return nullptr;
424}
425
426template <typename I>
427void DisableFeaturesRequest<I>::send_append_op_event() {
428 I &image_ctx = this->m_image_ctx;
429 CephContext *cct = image_ctx.cct;
430
431 if (!this->template append_op_event<
432 DisableFeaturesRequest<I>,
433 &DisableFeaturesRequest<I>::handle_append_op_event>(this)) {
434 send_remove_object_map();
435 }
436
437 ldout(cct, 20) << this << " " << __func__ << dendl;
438}
439
440template <typename I>
441Context *DisableFeaturesRequest<I>::handle_append_op_event(int *result) {
442 I &image_ctx = this->m_image_ctx;
443 CephContext *cct = image_ctx.cct;
444 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
445
446 if (*result < 0) {
447 lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result)
448 << dendl;
449 return handle_finish(*result);
450 }
451
452 send_remove_object_map();
453 return nullptr;
454}
455
456template <typename I>
457void DisableFeaturesRequest<I>::send_remove_object_map() {
458 I &image_ctx = this->m_image_ctx;
459 CephContext *cct = image_ctx.cct;
460 ldout(cct, 20) << this << " " << __func__ << dendl;
461
462 if ((m_features & RBD_FEATURE_OBJECT_MAP) == 0) {
463 send_set_features();
464 return;
465 }
466
467 Context *ctx = create_context_callback<
468 DisableFeaturesRequest<I>,
469 &DisableFeaturesRequest<I>::handle_remove_object_map>(this);
470
471 object_map::RemoveRequest<I> *req =
472 object_map::RemoveRequest<I>::create(&image_ctx, ctx);
473 req->send();
474}
475
476template <typename I>
477Context *DisableFeaturesRequest<I>::handle_remove_object_map(int *result) {
478 I &image_ctx = this->m_image_ctx;
479 CephContext *cct = image_ctx.cct;
480 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
481
482 if (*result < 0) {
483 lderr(cct) << "failed to remove object map: " << cpp_strerror(*result) << dendl;
484 return handle_finish(*result);
485 }
486
487 send_set_features();
488 return nullptr;
489}
490
491template <typename I>
492void DisableFeaturesRequest<I>::send_set_features() {
493 I &image_ctx = this->m_image_ctx;
494 CephContext *cct = image_ctx.cct;
495 ldout(cct, 20) << this << " " << __func__ << ": new_features="
496 << m_new_features << ", features_mask=" << m_features_mask
497 << dendl;
498
499 librados::ObjectWriteOperation op;
500 librbd::cls_client::set_features(&op, m_new_features, m_features_mask);
501
502 using klass = DisableFeaturesRequest<I>;
503 librados::AioCompletion *comp =
504 create_rados_callback<klass, &klass::handle_set_features>(this);
505 int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, comp, &op);
506 assert(r == 0);
507 comp->release();
508}
509
510template <typename I>
511Context *DisableFeaturesRequest<I>::handle_set_features(int *result) {
512 I &image_ctx = this->m_image_ctx;
513 CephContext *cct = image_ctx.cct;
514 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
515
516 if (*result == -EINVAL && (m_features_mask & RBD_FEATURE_JOURNALING) != 0) {
517 // NOTE: infernalis OSDs will not accept a mask with new features, so
518 // re-attempt with a reduced mask.
519 ldout(cct, 5) << this << " " << __func__
520 << ": re-attempt with a reduced mask" << dendl;
521 m_features_mask &= ~RBD_FEATURE_JOURNALING;
522 send_set_features();
523 }
524
525 if (*result < 0) {
526 lderr(cct) << "failed to update features: " << cpp_strerror(*result)
527 << dendl;
528 return handle_finish(*result);
529 }
530
531 send_update_flags();
532 return nullptr;
533}
534
535template <typename I>
536void DisableFeaturesRequest<I>::send_update_flags() {
537 I &image_ctx = this->m_image_ctx;
538 CephContext *cct = image_ctx.cct;
539
540 if (m_disable_flags == 0) {
541 send_notify_update();
542 return;
543 }
544
545 ldout(cct, 20) << this << " " << __func__ << ": disable_flags="
546 << m_disable_flags << dendl;
547
548 Context *ctx = create_context_callback<
549 DisableFeaturesRequest<I>,
550 &DisableFeaturesRequest<I>::handle_update_flags>(this);
551
552 image::SetFlagsRequest<I> *req =
553 image::SetFlagsRequest<I>::create(&image_ctx, 0, m_disable_flags, ctx);
554 req->send();
555}
556
557template <typename I>
558Context *DisableFeaturesRequest<I>::handle_update_flags(int *result) {
559 I &image_ctx = this->m_image_ctx;
560 CephContext *cct = image_ctx.cct;
561 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
562
563 if (*result < 0) {
564 lderr(cct) << "failed to update image flags: " << cpp_strerror(*result)
565 << dendl;
566 return handle_finish(*result);
567 }
568
569 send_notify_update();
570 return nullptr;
571}
572
573template <typename I>
574void DisableFeaturesRequest<I>::send_notify_update() {
575 I &image_ctx = this->m_image_ctx;
576 CephContext *cct = image_ctx.cct;
577 ldout(cct, 20) << this << " " << __func__ << dendl;
578
579 Context *ctx = create_context_callback<
580 DisableFeaturesRequest<I>,
581 &DisableFeaturesRequest<I>::handle_notify_update>(this);
582
583 image_ctx.notify_update(ctx);
584}
585
586template <typename I>
587Context *DisableFeaturesRequest<I>::handle_notify_update(int *result) {
588 I &image_ctx = this->m_image_ctx;
589 CephContext *cct = image_ctx.cct;
590 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
591
592 if (image_ctx.exclusive_lock == nullptr || !m_acquired_lock) {
593 return handle_finish(*result);
594 }
595
596 send_release_exclusive_lock();
597 return nullptr;
598}
599
600template <typename I>
601void DisableFeaturesRequest<I>::send_release_exclusive_lock() {
602 I &image_ctx = this->m_image_ctx;
603 CephContext *cct = image_ctx.cct;
604 ldout(cct, 20) << this << " " << __func__ << dendl;
605
606 Context *ctx = create_context_callback<
607 DisableFeaturesRequest<I>,
608 &DisableFeaturesRequest<I>::handle_release_exclusive_lock>(this);
609
610 image_ctx.exclusive_lock->release_lock(ctx);
611}
612
613template <typename I>
614Context *DisableFeaturesRequest<I>::handle_release_exclusive_lock(int *result) {
615 I &image_ctx = this->m_image_ctx;
616 CephContext *cct = image_ctx.cct;
617 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
618
619 return handle_finish(*result);
620}
621
622template <typename I>
623Context *DisableFeaturesRequest<I>::handle_finish(int r) {
624 I &image_ctx = this->m_image_ctx;
625 CephContext *cct = image_ctx.cct;
626 ldout(cct, 20) << this << " " << __func__ << ": r=" << r << dendl;
627
628 {
629 RWLock::WLocker locker(image_ctx.owner_lock);
630 if (image_ctx.exclusive_lock != nullptr && m_requests_blocked) {
631 image_ctx.exclusive_lock->unblock_requests();
632 }
633
634 image_ctx.io_work_queue->unblock_writes();
635 }
636 image_ctx.state->handle_prepare_lock_complete();
637
638 return this->create_context_finisher(r);
639}
640
641} // namespace operation
642} // namespace librbd
643
644template class librbd::operation::DisableFeaturesRequest<librbd::ImageCtx>;