]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/operation/DisableFeaturesRequest.cc
add subtree-ish sources for 12.0.3
[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
163 if (*result < 0) {
164 lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl;
165 return handle_finish(*result);
166 } else if (m_acquired_lock && (image_ctx.exclusive_lock == nullptr ||
167 !image_ctx.exclusive_lock->is_lock_owner())) {
168 lderr(cct) << "failed to acquire exclusive lock" << dendl;
169 *result = -EROFS;
170 return handle_finish(*result);
171 }
172
173 do {
174 RWLock::WLocker locker(image_ctx.owner_lock);
175
176 m_features &= image_ctx.features;
177 m_new_features = image_ctx.features & ~m_features;
178 m_features_mask = m_features;
179
180 if ((m_features & RBD_FEATURE_EXCLUSIVE_LOCK) != 0) {
181 if ((m_new_features & RBD_FEATURE_OBJECT_MAP) != 0 ||
182 (m_new_features & RBD_FEATURE_JOURNALING) != 0) {
183 lderr(cct) << "cannot disable exclusive-lock. object-map "
184 "or journaling must be disabled before "
185 "disabling exclusive-lock." << dendl;
186 *result = -EINVAL;
187 break;
188 }
189 m_features_mask |= (RBD_FEATURE_OBJECT_MAP |
190 RBD_FEATURE_JOURNALING);
191 }
192 if ((m_features & RBD_FEATURE_FAST_DIFF) != 0) {
193 m_disable_flags |= RBD_FLAG_FAST_DIFF_INVALID;
194 }
195 if ((m_features & RBD_FEATURE_OBJECT_MAP) != 0) {
196 if ((m_new_features & RBD_FEATURE_FAST_DIFF) != 0) {
197 lderr(cct) << "cannot disable object-map. fast-diff must be "
198 "disabled before disabling object-map." << dendl;
199 *result = -EINVAL;
200 break;
201 }
202 m_disable_flags |= RBD_FLAG_OBJECT_MAP_INVALID;
203 }
204 } while (false);
205
206 if (*result < 0) {
207 return handle_finish(*result);
208 }
209
210 send_get_mirror_mode();
211 return nullptr;
212}
213
214template <typename I>
215void DisableFeaturesRequest<I>::send_get_mirror_mode() {
216 I &image_ctx = this->m_image_ctx;
217 CephContext *cct = image_ctx.cct;
218
219 if ((m_features & RBD_FEATURE_JOURNALING) == 0) {
220 send_append_op_event();
221 return;
222 }
223
224 ldout(cct, 20) << this << " " << __func__ << dendl;
225
226 librados::ObjectReadOperation op;
227 cls_client::mirror_mode_get_start(&op);
228
229 using klass = DisableFeaturesRequest<I>;
230 librados::AioCompletion *comp =
231 create_rados_callback<klass, &klass::handle_get_mirror_mode>(this);
232 m_out_bl.clear();
233 int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
234 assert(r == 0);
235 comp->release();
236}
237
238template <typename I>
239Context *DisableFeaturesRequest<I>::handle_get_mirror_mode(int *result) {
240 I &image_ctx = this->m_image_ctx;
241 CephContext *cct = image_ctx.cct;
242 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
243
244 if (*result == 0) {
245 bufferlist::iterator it = m_out_bl.begin();
246 *result = cls_client::mirror_mode_get_finish(&it, &m_mirror_mode);
247 }
248
249 if (*result < 0 && *result != -ENOENT) {
250 lderr(cct) << "failed to retrieve pool mirror mode: "
251 << cpp_strerror(*result) << dendl;
252 return handle_finish(*result);
253 }
254
255 ldout(cct, 20) << this << " " << __func__ << ": m_mirror_mode="
256 << m_mirror_mode << dendl;
257
258 send_get_mirror_image();
259 return nullptr;
260}
261
262template <typename I>
263void DisableFeaturesRequest<I>::send_get_mirror_image() {
264 I &image_ctx = this->m_image_ctx;
265 CephContext *cct = image_ctx.cct;
266
267 if (m_mirror_mode != cls::rbd::MIRROR_MODE_IMAGE) {
268 send_disable_mirror_image();
269 return;
270 }
271
272 ldout(cct, 20) << this << " " << __func__ << dendl;
273
274 librados::ObjectReadOperation op;
275 cls_client::mirror_image_get_start(&op, image_ctx.id);
276
277 using klass = DisableFeaturesRequest<I>;
278 librados::AioCompletion *comp =
279 create_rados_callback<klass, &klass::handle_get_mirror_image>(this);
280 m_out_bl.clear();
281 int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
282 assert(r == 0);
283 comp->release();
284}
285
286template <typename I>
287Context *DisableFeaturesRequest<I>::handle_get_mirror_image(int *result) {
288 I &image_ctx = this->m_image_ctx;
289 CephContext *cct = image_ctx.cct;
290 ldout(cct, 20) << this << " " << __func__ << dendl;
291
292 cls::rbd::MirrorImage mirror_image;
293
294 if (*result == 0) {
295 bufferlist::iterator it = m_out_bl.begin();
296 *result = cls_client::mirror_image_get_finish(&it, &mirror_image);
297 }
298
299 if (*result < 0 && *result != -ENOENT) {
300 lderr(cct) << "failed to retrieve pool mirror image: "
301 << cpp_strerror(*result) << dendl;
302 return handle_finish(*result);
303 }
304
305 if ((mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) && !m_force) {
306 lderr(cct) << "cannot disable journaling: image mirroring "
307 << "enabled and mirror pool mode set to image"
308 << dendl;
309 *result = -EINVAL;
310 return handle_finish(*result);
311 }
312
313 send_disable_mirror_image();
314 return nullptr;
315}
316
317template <typename I>
318void DisableFeaturesRequest<I>::send_disable_mirror_image() {
319 I &image_ctx = this->m_image_ctx;
320 CephContext *cct = image_ctx.cct;
321
322 ldout(cct, 20) << this << " " << __func__ << dendl;
323
324 Context *ctx = create_context_callback<
325 DisableFeaturesRequest<I>,
326 &DisableFeaturesRequest<I>::handle_disable_mirror_image>(this);
327
328 mirror::DisableRequest<I> *req =
329 mirror::DisableRequest<I>::create(&image_ctx, m_force, true, ctx);
330 req->send();
331}
332
333template <typename I>
334Context *DisableFeaturesRequest<I>::handle_disable_mirror_image(int *result) {
335 I &image_ctx = this->m_image_ctx;
336 CephContext *cct = image_ctx.cct;
337 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
338
339 if (*result < 0) {
340 lderr(cct) << "failed to disable image mirroring: " << cpp_strerror(*result)
341 << dendl;
342 // not fatal
343 }
344
345 send_close_journal();
346 return nullptr;
347}
348
349template <typename I>
350void DisableFeaturesRequest<I>::send_close_journal() {
351 I &image_ctx = this->m_image_ctx;
352 CephContext *cct = image_ctx.cct;
353
354 {
355 RWLock::WLocker locker(image_ctx.owner_lock);
356 if (image_ctx.journal != nullptr) {
357
358 ldout(cct, 20) << this << " " << __func__ << dendl;
359
360 Context *ctx = create_context_callback<
361 DisableFeaturesRequest<I>,
362 &DisableFeaturesRequest<I>::handle_close_journal>(this);
363
364 image_ctx.journal->close(ctx);
365 return;
366 }
367 }
368
369 send_remove_journal();
370}
371
372template <typename I>
373Context *DisableFeaturesRequest<I>::handle_close_journal(int *result) {
374 I &image_ctx = this->m_image_ctx;
375 CephContext *cct = image_ctx.cct;
376 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
377
378 if (*result < 0) {
379 lderr(cct) << "failed to close image journal: " << cpp_strerror(*result)
380 << dendl;
381 return handle_finish(*result);
382 }
383
384 send_remove_journal();
385 return nullptr;
386}
387
388template <typename I>
389void DisableFeaturesRequest<I>::send_remove_journal() {
390 I &image_ctx = this->m_image_ctx;
391 CephContext *cct = image_ctx.cct;
392 ldout(cct, 20) << this << " " << __func__ << dendl;
393
394 Context *ctx = create_context_callback<
395 DisableFeaturesRequest<I>,
396 &DisableFeaturesRequest<I>::handle_remove_journal>(this);
397
398 journal::RemoveRequest<I> *req = journal::RemoveRequest<I>::create(
399 image_ctx.md_ctx, image_ctx.id, librbd::Journal<>::IMAGE_CLIENT_ID,
400 image_ctx.op_work_queue, ctx);
401
402 req->send();
403}
404
405template <typename I>
406Context *DisableFeaturesRequest<I>::handle_remove_journal(int *result) {
407 I &image_ctx = this->m_image_ctx;
408 CephContext *cct = image_ctx.cct;
409 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
410
411 if (*result < 0) {
412 lderr(cct) << "failed to remove image journal: " << cpp_strerror(*result)
413 << dendl;
414 return handle_finish(*result);
415 }
416
417 send_append_op_event();
418 return nullptr;
419}
420
421template <typename I>
422void DisableFeaturesRequest<I>::send_append_op_event() {
423 I &image_ctx = this->m_image_ctx;
424 CephContext *cct = image_ctx.cct;
425
426 if (!this->template append_op_event<
427 DisableFeaturesRequest<I>,
428 &DisableFeaturesRequest<I>::handle_append_op_event>(this)) {
429 send_remove_object_map();
430 }
431
432 ldout(cct, 20) << this << " " << __func__ << dendl;
433}
434
435template <typename I>
436Context *DisableFeaturesRequest<I>::handle_append_op_event(int *result) {
437 I &image_ctx = this->m_image_ctx;
438 CephContext *cct = image_ctx.cct;
439 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
440
441 if (*result < 0) {
442 lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result)
443 << dendl;
444 return handle_finish(*result);
445 }
446
447 send_remove_object_map();
448 return nullptr;
449}
450
451template <typename I>
452void DisableFeaturesRequest<I>::send_remove_object_map() {
453 I &image_ctx = this->m_image_ctx;
454 CephContext *cct = image_ctx.cct;
455 ldout(cct, 20) << this << " " << __func__ << dendl;
456
457 if ((m_features & RBD_FEATURE_OBJECT_MAP) == 0) {
458 send_set_features();
459 return;
460 }
461
462 Context *ctx = create_context_callback<
463 DisableFeaturesRequest<I>,
464 &DisableFeaturesRequest<I>::handle_remove_object_map>(this);
465
466 object_map::RemoveRequest<I> *req =
467 object_map::RemoveRequest<I>::create(&image_ctx, ctx);
468 req->send();
469}
470
471template <typename I>
472Context *DisableFeaturesRequest<I>::handle_remove_object_map(int *result) {
473 I &image_ctx = this->m_image_ctx;
474 CephContext *cct = image_ctx.cct;
475 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
476
477 if (*result < 0) {
478 lderr(cct) << "failed to remove object map: " << cpp_strerror(*result) << dendl;
479 return handle_finish(*result);
480 }
481
482 send_set_features();
483 return nullptr;
484}
485
486template <typename I>
487void DisableFeaturesRequest<I>::send_set_features() {
488 I &image_ctx = this->m_image_ctx;
489 CephContext *cct = image_ctx.cct;
490 ldout(cct, 20) << this << " " << __func__ << ": new_features="
491 << m_new_features << ", features_mask=" << m_features_mask
492 << dendl;
493
494 librados::ObjectWriteOperation op;
495 librbd::cls_client::set_features(&op, m_new_features, m_features_mask);
496
497 using klass = DisableFeaturesRequest<I>;
498 librados::AioCompletion *comp =
499 create_rados_callback<klass, &klass::handle_set_features>(this);
500 int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, comp, &op);
501 assert(r == 0);
502 comp->release();
503}
504
505template <typename I>
506Context *DisableFeaturesRequest<I>::handle_set_features(int *result) {
507 I &image_ctx = this->m_image_ctx;
508 CephContext *cct = image_ctx.cct;
509 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
510
511 if (*result == -EINVAL && (m_features_mask & RBD_FEATURE_JOURNALING) != 0) {
512 // NOTE: infernalis OSDs will not accept a mask with new features, so
513 // re-attempt with a reduced mask.
514 ldout(cct, 5) << this << " " << __func__
515 << ": re-attempt with a reduced mask" << dendl;
516 m_features_mask &= ~RBD_FEATURE_JOURNALING;
517 send_set_features();
518 }
519
520 if (*result < 0) {
521 lderr(cct) << "failed to update features: " << cpp_strerror(*result)
522 << dendl;
523 return handle_finish(*result);
524 }
525
526 send_update_flags();
527 return nullptr;
528}
529
530template <typename I>
531void DisableFeaturesRequest<I>::send_update_flags() {
532 I &image_ctx = this->m_image_ctx;
533 CephContext *cct = image_ctx.cct;
534
535 if (m_disable_flags == 0) {
536 send_notify_update();
537 return;
538 }
539
540 ldout(cct, 20) << this << " " << __func__ << ": disable_flags="
541 << m_disable_flags << dendl;
542
543 Context *ctx = create_context_callback<
544 DisableFeaturesRequest<I>,
545 &DisableFeaturesRequest<I>::handle_update_flags>(this);
546
547 image::SetFlagsRequest<I> *req =
548 image::SetFlagsRequest<I>::create(&image_ctx, 0, m_disable_flags, ctx);
549 req->send();
550}
551
552template <typename I>
553Context *DisableFeaturesRequest<I>::handle_update_flags(int *result) {
554 I &image_ctx = this->m_image_ctx;
555 CephContext *cct = image_ctx.cct;
556 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
557
558 if (*result < 0) {
559 lderr(cct) << "failed to update image flags: " << cpp_strerror(*result)
560 << dendl;
561 return handle_finish(*result);
562 }
563
564 send_notify_update();
565 return nullptr;
566}
567
568template <typename I>
569void DisableFeaturesRequest<I>::send_notify_update() {
570 I &image_ctx = this->m_image_ctx;
571 CephContext *cct = image_ctx.cct;
572 ldout(cct, 20) << this << " " << __func__ << dendl;
573
574 Context *ctx = create_context_callback<
575 DisableFeaturesRequest<I>,
576 &DisableFeaturesRequest<I>::handle_notify_update>(this);
577
578 image_ctx.notify_update(ctx);
579}
580
581template <typename I>
582Context *DisableFeaturesRequest<I>::handle_notify_update(int *result) {
583 I &image_ctx = this->m_image_ctx;
584 CephContext *cct = image_ctx.cct;
585 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
586
587 if (image_ctx.exclusive_lock == nullptr || !m_acquired_lock) {
588 return handle_finish(*result);
589 }
590
591 send_release_exclusive_lock();
592 return nullptr;
593}
594
595template <typename I>
596void DisableFeaturesRequest<I>::send_release_exclusive_lock() {
597 I &image_ctx = this->m_image_ctx;
598 CephContext *cct = image_ctx.cct;
599 ldout(cct, 20) << this << " " << __func__ << dendl;
600
601 Context *ctx = create_context_callback<
602 DisableFeaturesRequest<I>,
603 &DisableFeaturesRequest<I>::handle_release_exclusive_lock>(this);
604
605 image_ctx.exclusive_lock->release_lock(ctx);
606}
607
608template <typename I>
609Context *DisableFeaturesRequest<I>::handle_release_exclusive_lock(int *result) {
610 I &image_ctx = this->m_image_ctx;
611 CephContext *cct = image_ctx.cct;
612 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
613
614 return handle_finish(*result);
615}
616
617template <typename I>
618Context *DisableFeaturesRequest<I>::handle_finish(int r) {
619 I &image_ctx = this->m_image_ctx;
620 CephContext *cct = image_ctx.cct;
621 ldout(cct, 20) << this << " " << __func__ << ": r=" << r << dendl;
622
623 {
624 RWLock::WLocker locker(image_ctx.owner_lock);
625 if (image_ctx.exclusive_lock != nullptr && m_requests_blocked) {
626 image_ctx.exclusive_lock->unblock_requests();
627 }
628
629 image_ctx.io_work_queue->unblock_writes();
630 }
631 image_ctx.state->handle_prepare_lock_complete();
632
633 return this->create_context_finisher(r);
634}
635
636} // namespace operation
637} // namespace librbd
638
639template class librbd::operation::DisableFeaturesRequest<librbd::ImageCtx>;