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 assert(image_ctx.owner_lock.is_locked());
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 RWLock::WLocker 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 bufferlist::iterator it = m_out_bl.begin();
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 RWLock::WLocker 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;
178 m_new_features = image_ctx.features | m_features;
179 m_features_mask = m_features;
181 if ((m_features & RBD_FEATURE_OBJECT_MAP) != 0) {
182 if ((m_new_features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
183 lderr(cct) << "cannot enable object-map. exclusive-lock must be "
184 "enabled before enabling object-map." << dendl;
188 m_enable_flags |= RBD_FLAG_OBJECT_MAP_INVALID;
189 m_features_mask |= RBD_FEATURE_EXCLUSIVE_LOCK;
191 if ((m_features & RBD_FEATURE_FAST_DIFF) != 0) {
192 if ((m_new_features & RBD_FEATURE_OBJECT_MAP) == 0) {
193 lderr(cct) << "cannot enable fast-diff. object-map must be "
194 "enabled before enabling fast-diff." << dendl;
198 m_enable_flags |= RBD_FLAG_FAST_DIFF_INVALID;
199 m_features_mask |= (RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_EXCLUSIVE_LOCK);
201 if ((m_features & RBD_FEATURE_JOURNALING) != 0) {
202 if ((m_new_features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
203 lderr(cct) << "cannot enable journaling. exclusive-lock must be "
204 "enabled before enabling journaling." << dendl;
208 m_features_mask |= RBD_FEATURE_EXCLUSIVE_LOCK;
209 create_journal = true;
214 return handle_finish(*result);
216 if (create_journal) {
217 send_create_journal();
220 send_append_op_event();
224 template <typename I>
225 void EnableFeaturesRequest<I>::send_create_journal() {
226 I &image_ctx = this->m_image_ctx;
227 CephContext *cct = image_ctx.cct;
229 ldout(cct, 20) << this << " " << __func__ << dendl;
231 journal::TagData tag_data(librbd::Journal<>::LOCAL_MIRROR_UUID);
232 Context *ctx = create_context_callback<
233 EnableFeaturesRequest<I>,
234 &EnableFeaturesRequest<I>::handle_create_journal>(this);
236 journal::CreateRequest<I> *req = journal::CreateRequest<I>::create(
237 image_ctx.md_ctx, image_ctx.id, image_ctx.journal_order,
238 image_ctx.journal_splay_width, image_ctx.journal_pool,
239 cls::journal::Tag::TAG_CLASS_NEW, tag_data,
240 librbd::Journal<>::IMAGE_CLIENT_ID, image_ctx.op_work_queue, ctx);
245 template <typename I>
246 Context *EnableFeaturesRequest<I>::handle_create_journal(int *result) {
247 I &image_ctx = this->m_image_ctx;
248 CephContext *cct = image_ctx.cct;
249 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
252 lderr(cct) << "failed to create journal: " << cpp_strerror(*result)
254 return handle_finish(*result);
257 send_append_op_event();
261 template <typename I>
262 void EnableFeaturesRequest<I>::send_append_op_event() {
263 I &image_ctx = this->m_image_ctx;
264 CephContext *cct = image_ctx.cct;
266 if (!this->template append_op_event<
267 EnableFeaturesRequest<I>,
268 &EnableFeaturesRequest<I>::handle_append_op_event>(this)) {
272 ldout(cct, 20) << this << " " << __func__ << dendl;
275 template <typename I>
276 Context *EnableFeaturesRequest<I>::handle_append_op_event(int *result) {
277 I &image_ctx = this->m_image_ctx;
278 CephContext *cct = image_ctx.cct;
279 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
282 lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result)
284 return handle_finish(*result);
291 template <typename I>
292 void EnableFeaturesRequest<I>::send_update_flags() {
293 I &image_ctx = this->m_image_ctx;
294 CephContext *cct = image_ctx.cct;
296 if (m_enable_flags == 0) {
301 ldout(cct, 20) << this << " " << __func__ << ": enable_flags="
302 << m_enable_flags << dendl;
304 Context *ctx = create_context_callback<
305 EnableFeaturesRequest<I>,
306 &EnableFeaturesRequest<I>::handle_update_flags>(this);
308 image::SetFlagsRequest<I> *req =
309 image::SetFlagsRequest<I>::create(&image_ctx, m_enable_flags,
310 m_enable_flags, ctx);
314 template <typename I>
315 Context *EnableFeaturesRequest<I>::handle_update_flags(int *result) {
316 I &image_ctx = this->m_image_ctx;
317 CephContext *cct = image_ctx.cct;
318 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
321 lderr(cct) << "failed to update image flags: " << cpp_strerror(*result)
323 return handle_finish(*result);
330 template <typename I>
331 void EnableFeaturesRequest<I>::send_set_features() {
332 I &image_ctx = this->m_image_ctx;
333 CephContext *cct = image_ctx.cct;
334 ldout(cct, 20) << this << " " << __func__ << ": new_features="
335 << m_new_features << ", features_mask=" << m_features_mask
338 librados::ObjectWriteOperation op;
339 librbd::cls_client::set_features(&op, m_new_features, m_features_mask);
341 using klass = EnableFeaturesRequest<I>;
342 librados::AioCompletion *comp =
343 create_rados_callback<klass, &klass::handle_set_features>(this);
344 int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, comp, &op);
349 template <typename I>
350 Context *EnableFeaturesRequest<I>::handle_set_features(int *result) {
351 I &image_ctx = this->m_image_ctx;
352 CephContext *cct = image_ctx.cct;
353 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
356 lderr(cct) << "failed to update features: " << cpp_strerror(*result)
358 return handle_finish(*result);
361 send_create_object_map();
365 template <typename I>
366 void EnableFeaturesRequest<I>::send_create_object_map() {
367 I &image_ctx = this->m_image_ctx;
368 CephContext *cct = image_ctx.cct;
370 if (((image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0) ||
371 ((m_features & RBD_FEATURE_OBJECT_MAP) == 0)) {
372 send_enable_mirror_image();
376 ldout(cct, 20) << this << " " << __func__ << dendl;
378 Context *ctx = create_context_callback<
379 EnableFeaturesRequest<I>,
380 &EnableFeaturesRequest<I>::handle_create_object_map>(this);
382 object_map::CreateRequest<I> *req =
383 object_map::CreateRequest<I>::create(&image_ctx, ctx);
387 template <typename I>
388 Context *EnableFeaturesRequest<I>::handle_create_object_map(int *result) {
389 I &image_ctx = this->m_image_ctx;
390 CephContext *cct = image_ctx.cct;
391 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
394 lderr(cct) << "failed to create object map: " << cpp_strerror(*result)
396 return handle_finish(*result);
399 send_enable_mirror_image();
403 template <typename I>
404 void EnableFeaturesRequest<I>::send_enable_mirror_image() {
405 I &image_ctx = this->m_image_ctx;
406 CephContext *cct = image_ctx.cct;
407 ldout(cct, 20) << this << " " << __func__ << dendl;
409 if (!m_enable_mirroring) {
410 send_notify_update();
414 Context *ctx = create_context_callback<
415 EnableFeaturesRequest<I>,
416 &EnableFeaturesRequest<I>::handle_enable_mirror_image>(this);
418 mirror::EnableRequest<I> *req =
419 mirror::EnableRequest<I>::create(&image_ctx, ctx);
423 template <typename I>
424 Context *EnableFeaturesRequest<I>::handle_enable_mirror_image(int *result) {
425 I &image_ctx = this->m_image_ctx;
426 CephContext *cct = image_ctx.cct;
427 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
430 lderr(cct) << "failed to enable mirroring: " << cpp_strerror(*result)
435 send_notify_update();
439 template <typename I>
440 void EnableFeaturesRequest<I>::send_notify_update() {
441 I &image_ctx = this->m_image_ctx;
442 CephContext *cct = image_ctx.cct;
443 ldout(cct, 20) << this << " " << __func__ << dendl;
445 Context *ctx = create_context_callback<
446 EnableFeaturesRequest<I>,
447 &EnableFeaturesRequest<I>::handle_notify_update>(this);
449 image_ctx.notify_update(ctx);
452 template <typename I>
453 Context *EnableFeaturesRequest<I>::handle_notify_update(int *result) {
454 I &image_ctx = this->m_image_ctx;
455 CephContext *cct = image_ctx.cct;
456 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
458 return handle_finish(*result);
461 template <typename I>
462 Context *EnableFeaturesRequest<I>::handle_finish(int r) {
463 I &image_ctx = this->m_image_ctx;
464 CephContext *cct = image_ctx.cct;
465 ldout(cct, 20) << this << " " << __func__ << ": r=" << r << dendl;
468 RWLock::WLocker locker(image_ctx.owner_lock);
470 if (image_ctx.exclusive_lock != nullptr && m_requests_blocked) {
471 image_ctx.exclusive_lock->unblock_requests();
473 if (m_writes_blocked) {
474 image_ctx.io_work_queue->unblock_writes();
477 image_ctx.state->handle_prepare_lock_complete();
479 return this->create_context_finisher(r);
482 } // namespace operation
483 } // namespace librbd
485 template class librbd::operation::EnableFeaturesRequest<librbd::ImageCtx>;