1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
19 #define dout_subsys ceph_subsys_rbd
21 #define dout_prefix *_dout << "librbd::DisableFeaturesRequest: "
26 using util::create_async_context_callback
;
27 using util::create_context_callback
;
28 using util::create_rados_callback
;
31 DisableFeaturesRequest
<I
>::DisableFeaturesRequest(I
&image_ctx
,
33 uint64_t journal_op_tid
,
36 : Request
<I
>(image_ctx
, on_finish
, journal_op_tid
), m_features(features
),
41 void 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());
46 ldout(cct
, 20) << this << " " << __func__
<< ": features=" << m_features
53 bool 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
;
59 lderr(cct
) << "encountered error: " << cpp_strerror(r
) << dendl
;
65 void 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
;
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)));
77 Context
*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
;
83 lderr(cct
) << "failed to lock image: " << cpp_strerror(*result
) << dendl
;
84 return this->create_context_finisher(*result
);
92 void 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
;
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));
103 template <typename I
>
104 Context
*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
;
110 lderr(cct
) << "failed to block writes: " << cpp_strerror(*result
) << dendl
;
111 return handle_finish(*result
);
113 m_writes_blocked
= true;
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;
127 send_acquire_exclusive_lock();
131 template <typename I
>
132 void 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
;
137 Context
*ctx
= create_context_callback
<
138 DisableFeaturesRequest
<I
>,
139 &DisableFeaturesRequest
<I
>::handle_acquire_exclusive_lock
>(this);
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;
149 image_ctx
.exclusive_lock
->acquire_lock(ctx
);
157 template <typename I
>
158 Context
*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
;
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
;
170 return handle_finish(*result
);
174 RWLock::WLocker
locker(image_ctx
.owner_lock
);
176 m_features
&= image_ctx
.features
;
177 m_new_features
= image_ctx
.features
& ~m_features
;
178 m_features_mask
= m_features
;
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
;
189 m_features_mask
|= (RBD_FEATURE_OBJECT_MAP
|
190 RBD_FEATURE_JOURNALING
);
192 if ((m_features
& RBD_FEATURE_FAST_DIFF
) != 0) {
193 m_disable_flags
|= RBD_FLAG_FAST_DIFF_INVALID
;
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
;
202 m_disable_flags
|= RBD_FLAG_OBJECT_MAP_INVALID
;
207 return handle_finish(*result
);
210 send_get_mirror_mode();
214 template <typename I
>
215 void DisableFeaturesRequest
<I
>::send_get_mirror_mode() {
216 I
&image_ctx
= this->m_image_ctx
;
217 CephContext
*cct
= image_ctx
.cct
;
219 if ((m_features
& RBD_FEATURE_JOURNALING
) == 0) {
220 send_append_op_event();
224 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
226 librados::ObjectReadOperation op
;
227 cls_client::mirror_mode_get_start(&op
);
229 using klass
= DisableFeaturesRequest
<I
>;
230 librados::AioCompletion
*comp
=
231 create_rados_callback
<klass
, &klass::handle_get_mirror_mode
>(this);
233 int r
= image_ctx
.md_ctx
.aio_operate(RBD_MIRRORING
, comp
, &op
, &m_out_bl
);
238 template <typename I
>
239 Context
*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
;
245 bufferlist::iterator it
= m_out_bl
.begin();
246 *result
= cls_client::mirror_mode_get_finish(&it
, &m_mirror_mode
);
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
);
255 ldout(cct
, 20) << this << " " << __func__
<< ": m_mirror_mode="
256 << m_mirror_mode
<< dendl
;
258 send_get_mirror_image();
262 template <typename I
>
263 void DisableFeaturesRequest
<I
>::send_get_mirror_image() {
264 I
&image_ctx
= this->m_image_ctx
;
265 CephContext
*cct
= image_ctx
.cct
;
267 if (m_mirror_mode
!= cls::rbd::MIRROR_MODE_IMAGE
) {
268 send_disable_mirror_image();
272 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
274 librados::ObjectReadOperation op
;
275 cls_client::mirror_image_get_start(&op
, image_ctx
.id
);
277 using klass
= DisableFeaturesRequest
<I
>;
278 librados::AioCompletion
*comp
=
279 create_rados_callback
<klass
, &klass::handle_get_mirror_image
>(this);
281 int r
= image_ctx
.md_ctx
.aio_operate(RBD_MIRRORING
, comp
, &op
, &m_out_bl
);
286 template <typename I
>
287 Context
*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
;
292 cls::rbd::MirrorImage mirror_image
;
295 bufferlist::iterator it
= m_out_bl
.begin();
296 *result
= cls_client::mirror_image_get_finish(&it
, &mirror_image
);
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
);
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"
310 return handle_finish(*result
);
313 send_disable_mirror_image();
317 template <typename I
>
318 void DisableFeaturesRequest
<I
>::send_disable_mirror_image() {
319 I
&image_ctx
= this->m_image_ctx
;
320 CephContext
*cct
= image_ctx
.cct
;
322 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
324 Context
*ctx
= create_context_callback
<
325 DisableFeaturesRequest
<I
>,
326 &DisableFeaturesRequest
<I
>::handle_disable_mirror_image
>(this);
328 mirror::DisableRequest
<I
> *req
=
329 mirror::DisableRequest
<I
>::create(&image_ctx
, m_force
, true, ctx
);
333 template <typename I
>
334 Context
*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
;
340 lderr(cct
) << "failed to disable image mirroring: " << cpp_strerror(*result
)
345 send_close_journal();
349 template <typename I
>
350 void DisableFeaturesRequest
<I
>::send_close_journal() {
351 I
&image_ctx
= this->m_image_ctx
;
352 CephContext
*cct
= image_ctx
.cct
;
355 RWLock::WLocker
locker(image_ctx
.owner_lock
);
356 if (image_ctx
.journal
!= nullptr) {
357 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
359 std::swap(m_journal
, image_ctx
.journal
);
360 Context
*ctx
= create_context_callback
<
361 DisableFeaturesRequest
<I
>,
362 &DisableFeaturesRequest
<I
>::handle_close_journal
>(this);
364 m_journal
->close(ctx
);
369 send_remove_journal();
372 template <typename I
>
373 Context
*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
;
379 lderr(cct
) << "failed to close image journal: " << cpp_strerror(*result
)
383 assert(m_journal
!= nullptr);
387 send_remove_journal();
391 template <typename I
>
392 void DisableFeaturesRequest
<I
>::send_remove_journal() {
393 I
&image_ctx
= this->m_image_ctx
;
394 CephContext
*cct
= image_ctx
.cct
;
395 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
397 Context
*ctx
= create_context_callback
<
398 DisableFeaturesRequest
<I
>,
399 &DisableFeaturesRequest
<I
>::handle_remove_journal
>(this);
401 journal::RemoveRequest
<I
> *req
= journal::RemoveRequest
<I
>::create(
402 image_ctx
.md_ctx
, image_ctx
.id
, librbd::Journal
<>::IMAGE_CLIENT_ID
,
403 image_ctx
.op_work_queue
, ctx
);
408 template <typename I
>
409 Context
*DisableFeaturesRequest
<I
>::handle_remove_journal(int *result
) {
410 I
&image_ctx
= this->m_image_ctx
;
411 CephContext
*cct
= image_ctx
.cct
;
412 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
415 lderr(cct
) << "failed to remove image journal: " << cpp_strerror(*result
)
417 return handle_finish(*result
);
420 send_append_op_event();
424 template <typename I
>
425 void DisableFeaturesRequest
<I
>::send_append_op_event() {
426 I
&image_ctx
= this->m_image_ctx
;
427 CephContext
*cct
= image_ctx
.cct
;
429 if (!this->template append_op_event
<
430 DisableFeaturesRequest
<I
>,
431 &DisableFeaturesRequest
<I
>::handle_append_op_event
>(this)) {
432 send_remove_object_map();
435 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
438 template <typename I
>
439 Context
*DisableFeaturesRequest
<I
>::handle_append_op_event(int *result
) {
440 I
&image_ctx
= this->m_image_ctx
;
441 CephContext
*cct
= image_ctx
.cct
;
442 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
445 lderr(cct
) << "failed to commit journal entry: " << cpp_strerror(*result
)
447 return handle_finish(*result
);
450 send_remove_object_map();
454 template <typename I
>
455 void DisableFeaturesRequest
<I
>::send_remove_object_map() {
456 I
&image_ctx
= this->m_image_ctx
;
457 CephContext
*cct
= image_ctx
.cct
;
458 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
460 if ((m_features
& RBD_FEATURE_OBJECT_MAP
) == 0) {
465 Context
*ctx
= create_context_callback
<
466 DisableFeaturesRequest
<I
>,
467 &DisableFeaturesRequest
<I
>::handle_remove_object_map
>(this);
469 object_map::RemoveRequest
<I
> *req
=
470 object_map::RemoveRequest
<I
>::create(&image_ctx
, ctx
);
474 template <typename I
>
475 Context
*DisableFeaturesRequest
<I
>::handle_remove_object_map(int *result
) {
476 I
&image_ctx
= this->m_image_ctx
;
477 CephContext
*cct
= image_ctx
.cct
;
478 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
481 lderr(cct
) << "failed to remove object map: " << cpp_strerror(*result
) << dendl
;
482 return handle_finish(*result
);
489 template <typename I
>
490 void DisableFeaturesRequest
<I
>::send_set_features() {
491 I
&image_ctx
= this->m_image_ctx
;
492 CephContext
*cct
= image_ctx
.cct
;
493 ldout(cct
, 20) << this << " " << __func__
<< ": new_features="
494 << m_new_features
<< ", features_mask=" << m_features_mask
497 librados::ObjectWriteOperation op
;
498 librbd::cls_client::set_features(&op
, m_new_features
, m_features_mask
);
500 using klass
= DisableFeaturesRequest
<I
>;
501 librados::AioCompletion
*comp
=
502 create_rados_callback
<klass
, &klass::handle_set_features
>(this);
503 int r
= image_ctx
.md_ctx
.aio_operate(image_ctx
.header_oid
, comp
, &op
);
508 template <typename I
>
509 Context
*DisableFeaturesRequest
<I
>::handle_set_features(int *result
) {
510 I
&image_ctx
= this->m_image_ctx
;
511 CephContext
*cct
= image_ctx
.cct
;
512 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
514 if (*result
== -EINVAL
&& (m_features_mask
& RBD_FEATURE_JOURNALING
) != 0) {
515 // NOTE: infernalis OSDs will not accept a mask with new features, so
516 // re-attempt with a reduced mask.
517 ldout(cct
, 5) << this << " " << __func__
518 << ": re-attempt with a reduced mask" << dendl
;
519 m_features_mask
&= ~RBD_FEATURE_JOURNALING
;
524 lderr(cct
) << "failed to update features: " << cpp_strerror(*result
)
526 return handle_finish(*result
);
533 template <typename I
>
534 void DisableFeaturesRequest
<I
>::send_update_flags() {
535 I
&image_ctx
= this->m_image_ctx
;
536 CephContext
*cct
= image_ctx
.cct
;
538 if (m_disable_flags
== 0) {
539 send_notify_update();
543 ldout(cct
, 20) << this << " " << __func__
<< ": disable_flags="
544 << m_disable_flags
<< dendl
;
546 Context
*ctx
= create_context_callback
<
547 DisableFeaturesRequest
<I
>,
548 &DisableFeaturesRequest
<I
>::handle_update_flags
>(this);
550 image::SetFlagsRequest
<I
> *req
=
551 image::SetFlagsRequest
<I
>::create(&image_ctx
, 0, m_disable_flags
, ctx
);
555 template <typename I
>
556 Context
*DisableFeaturesRequest
<I
>::handle_update_flags(int *result
) {
557 I
&image_ctx
= this->m_image_ctx
;
558 CephContext
*cct
= image_ctx
.cct
;
559 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
562 lderr(cct
) << "failed to update image flags: " << cpp_strerror(*result
)
564 return handle_finish(*result
);
567 send_notify_update();
571 template <typename I
>
572 void DisableFeaturesRequest
<I
>::send_notify_update() {
573 I
&image_ctx
= this->m_image_ctx
;
574 CephContext
*cct
= image_ctx
.cct
;
575 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
577 Context
*ctx
= create_context_callback
<
578 DisableFeaturesRequest
<I
>,
579 &DisableFeaturesRequest
<I
>::handle_notify_update
>(this);
581 image_ctx
.notify_update(ctx
);
584 template <typename I
>
585 Context
*DisableFeaturesRequest
<I
>::handle_notify_update(int *result
) {
586 I
&image_ctx
= this->m_image_ctx
;
587 CephContext
*cct
= image_ctx
.cct
;
588 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
590 if (image_ctx
.exclusive_lock
== nullptr || !m_acquired_lock
) {
591 return handle_finish(*result
);
594 send_release_exclusive_lock();
598 template <typename I
>
599 void DisableFeaturesRequest
<I
>::send_release_exclusive_lock() {
600 I
&image_ctx
= this->m_image_ctx
;
601 CephContext
*cct
= image_ctx
.cct
;
602 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
604 Context
*ctx
= create_context_callback
<
605 DisableFeaturesRequest
<I
>,
606 &DisableFeaturesRequest
<I
>::handle_release_exclusive_lock
>(this);
608 image_ctx
.exclusive_lock
->release_lock(ctx
);
611 template <typename I
>
612 Context
*DisableFeaturesRequest
<I
>::handle_release_exclusive_lock(int *result
) {
613 I
&image_ctx
= this->m_image_ctx
;
614 CephContext
*cct
= image_ctx
.cct
;
615 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
617 return handle_finish(*result
);
620 template <typename I
>
621 Context
*DisableFeaturesRequest
<I
>::handle_finish(int r
) {
622 I
&image_ctx
= this->m_image_ctx
;
623 CephContext
*cct
= image_ctx
.cct
;
624 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << r
<< dendl
;
627 RWLock::WLocker
locker(image_ctx
.owner_lock
);
628 if (image_ctx
.exclusive_lock
!= nullptr && m_requests_blocked
) {
629 image_ctx
.exclusive_lock
->unblock_requests();
632 image_ctx
.io_work_queue
->unblock_writes();
634 image_ctx
.state
->handle_prepare_lock_complete();
636 return this->create_context_finisher(r
);
639 } // namespace operation
640 } // namespace librbd
642 template class librbd::operation::DisableFeaturesRequest
<librbd::ImageCtx
>;