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/EnableFeaturesRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "librbd/ExclusiveLock.h"
8 #include "librbd/ImageCtx.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/Journal.h"
11 #include "librbd/Utils.h"
12 #include "librbd/image/SetFlagsRequest.h"
13 #include "librbd/io/ImageRequestWQ.h"
14 #include "librbd/journal/CreateRequest.h"
15 #include "librbd/mirror/EnableRequest.h"
16 #include "librbd/object_map/CreateRequest.h"
18 #define dout_subsys ceph_subsys_rbd
20 #define dout_prefix *_dout << "librbd::EnableFeaturesRequest: "
25 using util::create_async_context_callback
;
26 using util::create_context_callback
;
27 using util::create_rados_callback
;
30 EnableFeaturesRequest
<I
>::EnableFeaturesRequest(I
&image_ctx
,
32 uint64_t journal_op_tid
,
34 : Request
<I
>(image_ctx
, on_finish
, journal_op_tid
), m_features(features
) {
38 void EnableFeaturesRequest
<I
>::send_op() {
39 I
&image_ctx
= this->m_image_ctx
;
40 CephContext
*cct
= image_ctx
.cct
;
41 ceph_assert(ceph_mutex_is_locked(image_ctx
.owner_lock
));
43 ldout(cct
, 20) << this << " " << __func__
<< ": features=" << m_features
49 bool EnableFeaturesRequest
<I
>::should_complete(int r
) {
50 I
&image_ctx
= this->m_image_ctx
;
51 CephContext
*cct
= image_ctx
.cct
;
52 ldout(cct
, 20) << this << " " << __func__
<< " r=" << r
<< dendl
;
55 lderr(cct
) << "encountered error: " << cpp_strerror(r
) << dendl
;
61 void EnableFeaturesRequest
<I
>::send_prepare_lock() {
62 I
&image_ctx
= this->m_image_ctx
;
63 CephContext
*cct
= image_ctx
.cct
;
64 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
66 image_ctx
.state
->prepare_lock(create_async_context_callback(
67 image_ctx
, create_context_callback
<
68 EnableFeaturesRequest
<I
>,
69 &EnableFeaturesRequest
<I
>::handle_prepare_lock
>(this)));
73 Context
*EnableFeaturesRequest
<I
>::handle_prepare_lock(int *result
) {
74 I
&image_ctx
= this->m_image_ctx
;
75 CephContext
*cct
= image_ctx
.cct
;
76 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
79 lderr(cct
) << "failed to lock image: " << cpp_strerror(*result
) << dendl
;
80 return this->create_context_finisher(*result
);
88 void EnableFeaturesRequest
<I
>::send_block_writes() {
89 I
&image_ctx
= this->m_image_ctx
;
90 CephContext
*cct
= image_ctx
.cct
;
91 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
93 std::unique_lock locker
{image_ctx
.owner_lock
};
94 image_ctx
.io_work_queue
->block_writes(create_context_callback
<
95 EnableFeaturesRequest
<I
>,
96 &EnableFeaturesRequest
<I
>::handle_block_writes
>(this));
100 Context
*EnableFeaturesRequest
<I
>::handle_block_writes(int *result
) {
101 I
&image_ctx
= this->m_image_ctx
;
102 CephContext
*cct
= image_ctx
.cct
;
103 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
106 lderr(cct
) << "failed to block writes: " << cpp_strerror(*result
) << dendl
;
107 return handle_finish(*result
);
109 m_writes_blocked
= true;
111 send_get_mirror_mode();
115 template <typename I
>
116 void EnableFeaturesRequest
<I
>::send_get_mirror_mode() {
117 I
&image_ctx
= this->m_image_ctx
;
118 CephContext
*cct
= image_ctx
.cct
;
120 if ((m_features
& RBD_FEATURE_JOURNALING
) == 0) {
121 Context
*ctx
= create_context_callback
<
122 EnableFeaturesRequest
<I
>,
123 &EnableFeaturesRequest
<I
>::handle_get_mirror_mode
>(this);
124 ctx
->complete(-ENOENT
);
128 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
130 librados::ObjectReadOperation op
;
131 cls_client::mirror_mode_get_start(&op
);
133 using klass
= EnableFeaturesRequest
<I
>;
134 librados::AioCompletion
*comp
=
135 create_rados_callback
<klass
, &klass::handle_get_mirror_mode
>(this);
137 int r
= image_ctx
.md_ctx
.aio_operate(RBD_MIRRORING
, comp
, &op
, &m_out_bl
);
142 template <typename I
>
143 Context
*EnableFeaturesRequest
<I
>::handle_get_mirror_mode(int *result
) {
144 I
&image_ctx
= this->m_image_ctx
;
145 CephContext
*cct
= image_ctx
.cct
;
146 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
148 cls::rbd::MirrorMode mirror_mode
= cls::rbd::MIRROR_MODE_DISABLED
;
150 auto it
= m_out_bl
.cbegin();
151 *result
= cls_client::mirror_mode_get_finish(&it
, &mirror_mode
);
152 } else if (*result
== -ENOENT
) {
157 lderr(cct
) << "failed to retrieve pool mirror mode: "
158 << cpp_strerror(*result
) << dendl
;
159 return handle_finish(*result
);
162 m_enable_mirroring
= (mirror_mode
== cls::rbd::MIRROR_MODE_POOL
);
164 bool create_journal
= false;
166 std::unique_lock locker
{image_ctx
.owner_lock
};
168 // avoid accepting new requests from peers while we manipulate
169 // the image features
170 if (image_ctx
.exclusive_lock
!= nullptr &&
171 (image_ctx
.journal
== nullptr ||
172 !image_ctx
.journal
->is_journal_replaying())) {
173 image_ctx
.exclusive_lock
->block_requests(0);
174 m_requests_blocked
= true;
177 m_features
&= ~image_ctx
.features
;
179 // interlock object-map and fast-diff together
180 if (((m_features
& RBD_FEATURE_OBJECT_MAP
) != 0) ||
181 ((m_features
& RBD_FEATURE_FAST_DIFF
) != 0)) {
182 m_features
|= (RBD_FEATURE_OBJECT_MAP
| RBD_FEATURE_FAST_DIFF
);
185 m_new_features
= image_ctx
.features
| m_features
;
186 m_features_mask
= m_features
;
188 if ((m_features
& RBD_FEATURE_OBJECT_MAP
) != 0) {
189 if ((m_new_features
& RBD_FEATURE_EXCLUSIVE_LOCK
) == 0) {
190 lderr(cct
) << "cannot enable object-map. exclusive-lock must be "
191 "enabled before enabling object-map." << dendl
;
195 m_enable_flags
|= RBD_FLAG_OBJECT_MAP_INVALID
;
196 m_features_mask
|= (RBD_FEATURE_EXCLUSIVE_LOCK
| RBD_FEATURE_FAST_DIFF
);
198 if ((m_features
& RBD_FEATURE_FAST_DIFF
) != 0) {
199 m_enable_flags
|= RBD_FLAG_FAST_DIFF_INVALID
;
200 m_features_mask
|= (RBD_FEATURE_EXCLUSIVE_LOCK
| RBD_FEATURE_OBJECT_MAP
);
203 if ((m_features
& RBD_FEATURE_JOURNALING
) != 0) {
204 if ((m_new_features
& RBD_FEATURE_EXCLUSIVE_LOCK
) == 0) {
205 lderr(cct
) << "cannot enable journaling. exclusive-lock must be "
206 "enabled before enabling journaling." << dendl
;
210 m_features_mask
|= RBD_FEATURE_EXCLUSIVE_LOCK
;
211 create_journal
= true;
216 return handle_finish(*result
);
218 if (create_journal
) {
219 send_create_journal();
222 send_append_op_event();
226 template <typename I
>
227 void EnableFeaturesRequest
<I
>::send_create_journal() {
228 I
&image_ctx
= this->m_image_ctx
;
229 CephContext
*cct
= image_ctx
.cct
;
231 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
233 journal::TagData
tag_data(librbd::Journal
<>::LOCAL_MIRROR_UUID
);
234 Context
*ctx
= create_context_callback
<
235 EnableFeaturesRequest
<I
>,
236 &EnableFeaturesRequest
<I
>::handle_create_journal
>(this);
238 journal::CreateRequest
<I
> *req
= journal::CreateRequest
<I
>::create(
239 image_ctx
.md_ctx
, image_ctx
.id
,
240 image_ctx
.config
.template get_val
<uint64_t>("rbd_journal_order"),
241 image_ctx
.config
.template get_val
<uint64_t>("rbd_journal_splay_width"),
242 image_ctx
.config
.template get_val
<std::string
>("rbd_journal_pool"),
243 cls::journal::Tag::TAG_CLASS_NEW
, tag_data
,
244 librbd::Journal
<>::IMAGE_CLIENT_ID
, image_ctx
.op_work_queue
, ctx
);
249 template <typename I
>
250 Context
*EnableFeaturesRequest
<I
>::handle_create_journal(int *result
) {
251 I
&image_ctx
= this->m_image_ctx
;
252 CephContext
*cct
= image_ctx
.cct
;
253 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
256 lderr(cct
) << "failed to create journal: " << cpp_strerror(*result
)
258 return handle_finish(*result
);
261 send_append_op_event();
265 template <typename I
>
266 void EnableFeaturesRequest
<I
>::send_append_op_event() {
267 I
&image_ctx
= this->m_image_ctx
;
268 CephContext
*cct
= image_ctx
.cct
;
270 if (!this->template append_op_event
<
271 EnableFeaturesRequest
<I
>,
272 &EnableFeaturesRequest
<I
>::handle_append_op_event
>(this)) {
276 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
279 template <typename I
>
280 Context
*EnableFeaturesRequest
<I
>::handle_append_op_event(int *result
) {
281 I
&image_ctx
= this->m_image_ctx
;
282 CephContext
*cct
= image_ctx
.cct
;
283 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
286 lderr(cct
) << "failed to commit journal entry: " << cpp_strerror(*result
)
288 return handle_finish(*result
);
295 template <typename I
>
296 void EnableFeaturesRequest
<I
>::send_update_flags() {
297 I
&image_ctx
= this->m_image_ctx
;
298 CephContext
*cct
= image_ctx
.cct
;
300 if (m_enable_flags
== 0) {
305 ldout(cct
, 20) << this << " " << __func__
<< ": enable_flags="
306 << m_enable_flags
<< dendl
;
308 Context
*ctx
= create_context_callback
<
309 EnableFeaturesRequest
<I
>,
310 &EnableFeaturesRequest
<I
>::handle_update_flags
>(this);
312 image::SetFlagsRequest
<I
> *req
=
313 image::SetFlagsRequest
<I
>::create(&image_ctx
, m_enable_flags
,
314 m_enable_flags
, ctx
);
318 template <typename I
>
319 Context
*EnableFeaturesRequest
<I
>::handle_update_flags(int *result
) {
320 I
&image_ctx
= this->m_image_ctx
;
321 CephContext
*cct
= image_ctx
.cct
;
322 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
325 lderr(cct
) << "failed to update image flags: " << cpp_strerror(*result
)
327 return handle_finish(*result
);
334 template <typename I
>
335 void EnableFeaturesRequest
<I
>::send_set_features() {
336 I
&image_ctx
= this->m_image_ctx
;
337 CephContext
*cct
= image_ctx
.cct
;
338 ldout(cct
, 20) << this << " " << __func__
<< ": new_features="
339 << m_new_features
<< ", features_mask=" << m_features_mask
342 librados::ObjectWriteOperation op
;
343 librbd::cls_client::set_features(&op
, m_new_features
, m_features_mask
);
345 using klass
= EnableFeaturesRequest
<I
>;
346 librados::AioCompletion
*comp
=
347 create_rados_callback
<klass
, &klass::handle_set_features
>(this);
348 int r
= image_ctx
.md_ctx
.aio_operate(image_ctx
.header_oid
, comp
, &op
);
353 template <typename I
>
354 Context
*EnableFeaturesRequest
<I
>::handle_set_features(int *result
) {
355 I
&image_ctx
= this->m_image_ctx
;
356 CephContext
*cct
= image_ctx
.cct
;
357 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
360 lderr(cct
) << "failed to update features: " << cpp_strerror(*result
)
362 return handle_finish(*result
);
365 send_create_object_map();
369 template <typename I
>
370 void EnableFeaturesRequest
<I
>::send_create_object_map() {
371 I
&image_ctx
= this->m_image_ctx
;
372 CephContext
*cct
= image_ctx
.cct
;
374 if (((image_ctx
.features
& RBD_FEATURE_OBJECT_MAP
) != 0) ||
375 ((m_features
& RBD_FEATURE_OBJECT_MAP
) == 0)) {
376 send_enable_mirror_image();
380 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
382 Context
*ctx
= create_context_callback
<
383 EnableFeaturesRequest
<I
>,
384 &EnableFeaturesRequest
<I
>::handle_create_object_map
>(this);
386 object_map::CreateRequest
<I
> *req
=
387 object_map::CreateRequest
<I
>::create(&image_ctx
, ctx
);
391 template <typename I
>
392 Context
*EnableFeaturesRequest
<I
>::handle_create_object_map(int *result
) {
393 I
&image_ctx
= this->m_image_ctx
;
394 CephContext
*cct
= image_ctx
.cct
;
395 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
398 lderr(cct
) << "failed to create object map: " << cpp_strerror(*result
)
400 return handle_finish(*result
);
403 send_enable_mirror_image();
407 template <typename I
>
408 void EnableFeaturesRequest
<I
>::send_enable_mirror_image() {
409 I
&image_ctx
= this->m_image_ctx
;
410 CephContext
*cct
= image_ctx
.cct
;
412 if (!m_enable_mirroring
) {
413 send_notify_update();
417 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
419 Context
*ctx
= create_context_callback
<
420 EnableFeaturesRequest
<I
>,
421 &EnableFeaturesRequest
<I
>::handle_enable_mirror_image
>(this);
423 auto req
= mirror::EnableRequest
<I
>::create(
424 &image_ctx
, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL
, "", false, ctx
);
428 template <typename I
>
429 Context
*EnableFeaturesRequest
<I
>::handle_enable_mirror_image(int *result
) {
430 I
&image_ctx
= this->m_image_ctx
;
431 CephContext
*cct
= image_ctx
.cct
;
432 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
435 lderr(cct
) << "failed to enable mirroring: " << cpp_strerror(*result
)
440 send_notify_update();
444 template <typename I
>
445 void EnableFeaturesRequest
<I
>::send_notify_update() {
446 I
&image_ctx
= this->m_image_ctx
;
447 CephContext
*cct
= image_ctx
.cct
;
448 ldout(cct
, 20) << this << " " << __func__
<< dendl
;
450 Context
*ctx
= create_context_callback
<
451 EnableFeaturesRequest
<I
>,
452 &EnableFeaturesRequest
<I
>::handle_notify_update
>(this);
454 image_ctx
.notify_update(ctx
);
457 template <typename I
>
458 Context
*EnableFeaturesRequest
<I
>::handle_notify_update(int *result
) {
459 I
&image_ctx
= this->m_image_ctx
;
460 CephContext
*cct
= image_ctx
.cct
;
461 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << *result
<< dendl
;
463 return handle_finish(*result
);
466 template <typename I
>
467 Context
*EnableFeaturesRequest
<I
>::handle_finish(int r
) {
468 I
&image_ctx
= this->m_image_ctx
;
469 CephContext
*cct
= image_ctx
.cct
;
470 ldout(cct
, 20) << this << " " << __func__
<< ": r=" << r
<< dendl
;
473 std::unique_lock locker
{image_ctx
.owner_lock
};
475 if (image_ctx
.exclusive_lock
!= nullptr && m_requests_blocked
) {
476 image_ctx
.exclusive_lock
->unblock_requests();
478 if (m_writes_blocked
) {
479 image_ctx
.io_work_queue
->unblock_writes();
482 image_ctx
.state
->handle_prepare_lock_complete();
484 return this->create_context_finisher(r
);
487 } // namespace operation
488 } // namespace librbd
490 template class librbd::operation::EnableFeaturesRequest
<librbd::ImageCtx
>;