]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/operation/EnableFeaturesRequest.cc
update source to Ceph Pacific 16.2.2
[ceph.git] / ceph / src / librbd / operation / EnableFeaturesRequest.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/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"
f67539c2 13#include "librbd/io/ImageDispatcherInterface.h"
7c673cae 14#include "librbd/journal/CreateRequest.h"
f67539c2 15#include "librbd/journal/TypeTraits.h"
7c673cae
FG
16#include "librbd/mirror/EnableRequest.h"
17#include "librbd/object_map/CreateRequest.h"
18
19#define dout_subsys ceph_subsys_rbd
20#undef dout_prefix
21#define dout_prefix *_dout << "librbd::EnableFeaturesRequest: "
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>
31EnableFeaturesRequest<I>::EnableFeaturesRequest(I &image_ctx,
32 Context *on_finish,
33 uint64_t journal_op_tid,
34 uint64_t features)
35 : Request<I>(image_ctx, on_finish, journal_op_tid), m_features(features) {
36}
37
38template <typename I>
39void EnableFeaturesRequest<I>::send_op() {
40 I &image_ctx = this->m_image_ctx;
41 CephContext *cct = image_ctx.cct;
9f95a23c 42 ceph_assert(ceph_mutex_is_locked(image_ctx.owner_lock));
7c673cae
FG
43
44 ldout(cct, 20) << this << " " << __func__ << ": features=" << m_features
45 << dendl;
46 send_prepare_lock();
47}
48
49template <typename I>
50bool EnableFeaturesRequest<I>::should_complete(int r) {
51 I &image_ctx = this->m_image_ctx;
52 CephContext *cct = image_ctx.cct;
11fdf7f2 53 ldout(cct, 20) << this << " " << __func__ << " r=" << r << dendl;
7c673cae
FG
54
55 if (r < 0) {
56 lderr(cct) << "encountered error: " << cpp_strerror(r) << dendl;
57 }
58 return true;
59}
60
61template <typename I>
62void EnableFeaturesRequest<I>::send_prepare_lock() {
63 I &image_ctx = this->m_image_ctx;
64 CephContext *cct = image_ctx.cct;
65 ldout(cct, 20) << this << " " << __func__ << dendl;
66
67 image_ctx.state->prepare_lock(create_async_context_callback(
68 image_ctx, create_context_callback<
69 EnableFeaturesRequest<I>,
70 &EnableFeaturesRequest<I>::handle_prepare_lock>(this)));
71}
72
73template <typename I>
74Context *EnableFeaturesRequest<I>::handle_prepare_lock(int *result) {
75 I &image_ctx = this->m_image_ctx;
76 CephContext *cct = image_ctx.cct;
77 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
78
79 if (*result < 0) {
80 lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl;
81 return this->create_context_finisher(*result);
82 }
83
84 send_block_writes();
85 return nullptr;
86}
87
88template <typename I>
89void EnableFeaturesRequest<I>::send_block_writes() {
90 I &image_ctx = this->m_image_ctx;
91 CephContext *cct = image_ctx.cct;
92 ldout(cct, 20) << this << " " << __func__ << dendl;
93
9f95a23c 94 std::unique_lock locker{image_ctx.owner_lock};
f67539c2 95 image_ctx.io_image_dispatcher->block_writes(create_context_callback<
7c673cae
FG
96 EnableFeaturesRequest<I>,
97 &EnableFeaturesRequest<I>::handle_block_writes>(this));
98}
99
100template <typename I>
101Context *EnableFeaturesRequest<I>::handle_block_writes(int *result) {
102 I &image_ctx = this->m_image_ctx;
103 CephContext *cct = image_ctx.cct;
104 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
105
106 if (*result < 0) {
107 lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl;
108 return handle_finish(*result);
109 }
110 m_writes_blocked = true;
111
112 send_get_mirror_mode();
113 return nullptr;
114}
115
116template <typename I>
117void EnableFeaturesRequest<I>::send_get_mirror_mode() {
118 I &image_ctx = this->m_image_ctx;
119 CephContext *cct = image_ctx.cct;
120
121 if ((m_features & RBD_FEATURE_JOURNALING) == 0) {
122 Context *ctx = create_context_callback<
123 EnableFeaturesRequest<I>,
124 &EnableFeaturesRequest<I>::handle_get_mirror_mode>(this);
125 ctx->complete(-ENOENT);
126 return;
127 }
128
129 ldout(cct, 20) << this << " " << __func__ << dendl;
130
131 librados::ObjectReadOperation op;
132 cls_client::mirror_mode_get_start(&op);
133
134 using klass = EnableFeaturesRequest<I>;
135 librados::AioCompletion *comp =
136 create_rados_callback<klass, &klass::handle_get_mirror_mode>(this);
137 m_out_bl.clear();
138 int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
11fdf7f2 139 ceph_assert(r == 0);
7c673cae
FG
140 comp->release();
141}
142
143template <typename I>
144Context *EnableFeaturesRequest<I>::handle_get_mirror_mode(int *result) {
145 I &image_ctx = this->m_image_ctx;
146 CephContext *cct = image_ctx.cct;
147 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
148
149 cls::rbd::MirrorMode mirror_mode = cls::rbd::MIRROR_MODE_DISABLED;
150 if (*result == 0) {
11fdf7f2 151 auto it = m_out_bl.cbegin();
7c673cae
FG
152 *result = cls_client::mirror_mode_get_finish(&it, &mirror_mode);
153 } else if (*result == -ENOENT) {
154 *result = 0;
155 }
156
157 if (*result < 0) {
158 lderr(cct) << "failed to retrieve pool mirror mode: "
159 << cpp_strerror(*result) << dendl;
160 return handle_finish(*result);
161 }
162
163 m_enable_mirroring = (mirror_mode == cls::rbd::MIRROR_MODE_POOL);
164
165 bool create_journal = false;
166 do {
9f95a23c 167 std::unique_lock locker{image_ctx.owner_lock};
7c673cae
FG
168
169 // avoid accepting new requests from peers while we manipulate
170 // the image features
171 if (image_ctx.exclusive_lock != nullptr &&
172 (image_ctx.journal == nullptr ||
173 !image_ctx.journal->is_journal_replaying())) {
174 image_ctx.exclusive_lock->block_requests(0);
175 m_requests_blocked = true;
176 }
177
178 m_features &= ~image_ctx.features;
81eedcae
TL
179
180 // interlock object-map and fast-diff together
181 if (((m_features & RBD_FEATURE_OBJECT_MAP) != 0) ||
182 ((m_features & RBD_FEATURE_FAST_DIFF) != 0)) {
183 m_features |= (RBD_FEATURE_OBJECT_MAP | RBD_FEATURE_FAST_DIFF);
184 }
185
7c673cae
FG
186 m_new_features = image_ctx.features | m_features;
187 m_features_mask = m_features;
188
189 if ((m_features & RBD_FEATURE_OBJECT_MAP) != 0) {
190 if ((m_new_features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
191 lderr(cct) << "cannot enable object-map. exclusive-lock must be "
192 "enabled before enabling object-map." << dendl;
193 *result = -EINVAL;
194 break;
195 }
196 m_enable_flags |= RBD_FLAG_OBJECT_MAP_INVALID;
81eedcae 197 m_features_mask |= (RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_FAST_DIFF);
7c673cae
FG
198 }
199 if ((m_features & RBD_FEATURE_FAST_DIFF) != 0) {
7c673cae 200 m_enable_flags |= RBD_FLAG_FAST_DIFF_INVALID;
81eedcae 201 m_features_mask |= (RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_OBJECT_MAP);
7c673cae 202 }
81eedcae 203
7c673cae
FG
204 if ((m_features & RBD_FEATURE_JOURNALING) != 0) {
205 if ((m_new_features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
206 lderr(cct) << "cannot enable journaling. exclusive-lock must be "
207 "enabled before enabling journaling." << dendl;
208 *result = -EINVAL;
209 break;
210 }
211 m_features_mask |= RBD_FEATURE_EXCLUSIVE_LOCK;
212 create_journal = true;
213 }
214 } while (false);
215
216 if (*result < 0) {
217 return handle_finish(*result);
218 }
219 if (create_journal) {
220 send_create_journal();
221 return nullptr;
222 }
223 send_append_op_event();
224 return nullptr;
225}
226
227template <typename I>
228void EnableFeaturesRequest<I>::send_create_journal() {
229 I &image_ctx = this->m_image_ctx;
230 CephContext *cct = image_ctx.cct;
231
232 ldout(cct, 20) << this << " " << __func__ << dendl;
233
234 journal::TagData tag_data(librbd::Journal<>::LOCAL_MIRROR_UUID);
235 Context *ctx = create_context_callback<
236 EnableFeaturesRequest<I>,
237 &EnableFeaturesRequest<I>::handle_create_journal>(this);
238
f67539c2
TL
239 typename journal::TypeTraits<I>::ContextWQ* context_wq;
240 Journal<I>::get_work_queue(cct, &context_wq);
241
7c673cae 242 journal::CreateRequest<I> *req = journal::CreateRequest<I>::create(
11fdf7f2
TL
243 image_ctx.md_ctx, image_ctx.id,
244 image_ctx.config.template get_val<uint64_t>("rbd_journal_order"),
245 image_ctx.config.template get_val<uint64_t>("rbd_journal_splay_width"),
246 image_ctx.config.template get_val<std::string>("rbd_journal_pool"),
7c673cae 247 cls::journal::Tag::TAG_CLASS_NEW, tag_data,
f67539c2 248 librbd::Journal<>::IMAGE_CLIENT_ID, context_wq, ctx);
7c673cae
FG
249
250 req->send();
251}
252
253template <typename I>
254Context *EnableFeaturesRequest<I>::handle_create_journal(int *result) {
255 I &image_ctx = this->m_image_ctx;
256 CephContext *cct = image_ctx.cct;
257 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
258
259 if (*result < 0) {
260 lderr(cct) << "failed to create journal: " << cpp_strerror(*result)
261 << dendl;
262 return handle_finish(*result);
263 }
264
265 send_append_op_event();
266 return nullptr;
267}
268
269template <typename I>
270void EnableFeaturesRequest<I>::send_append_op_event() {
271 I &image_ctx = this->m_image_ctx;
272 CephContext *cct = image_ctx.cct;
273
274 if (!this->template append_op_event<
275 EnableFeaturesRequest<I>,
276 &EnableFeaturesRequest<I>::handle_append_op_event>(this)) {
277 send_update_flags();
278 }
279
280 ldout(cct, 20) << this << " " << __func__ << dendl;
281}
282
283template <typename I>
284Context *EnableFeaturesRequest<I>::handle_append_op_event(int *result) {
285 I &image_ctx = this->m_image_ctx;
286 CephContext *cct = image_ctx.cct;
287 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
288
289 if (*result < 0) {
290 lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result)
291 << dendl;
292 return handle_finish(*result);
293 }
294
295 send_update_flags();
296 return nullptr;
297}
298
299template <typename I>
300void EnableFeaturesRequest<I>::send_update_flags() {
301 I &image_ctx = this->m_image_ctx;
302 CephContext *cct = image_ctx.cct;
303
304 if (m_enable_flags == 0) {
305 send_set_features();
306 return;
307 }
308
309 ldout(cct, 20) << this << " " << __func__ << ": enable_flags="
310 << m_enable_flags << dendl;
311
312 Context *ctx = create_context_callback<
313 EnableFeaturesRequest<I>,
314 &EnableFeaturesRequest<I>::handle_update_flags>(this);
315
316 image::SetFlagsRequest<I> *req =
317 image::SetFlagsRequest<I>::create(&image_ctx, m_enable_flags,
318 m_enable_flags, ctx);
319 req->send();
320}
321
322template <typename I>
323Context *EnableFeaturesRequest<I>::handle_update_flags(int *result) {
324 I &image_ctx = this->m_image_ctx;
325 CephContext *cct = image_ctx.cct;
326 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
327
328 if (*result < 0) {
329 lderr(cct) << "failed to update image flags: " << cpp_strerror(*result)
330 << dendl;
331 return handle_finish(*result);
332 }
333
334 send_set_features();
335 return nullptr;
336}
337
338template <typename I>
339void EnableFeaturesRequest<I>::send_set_features() {
340 I &image_ctx = this->m_image_ctx;
341 CephContext *cct = image_ctx.cct;
342 ldout(cct, 20) << this << " " << __func__ << ": new_features="
343 << m_new_features << ", features_mask=" << m_features_mask
344 << dendl;
345
346 librados::ObjectWriteOperation op;
347 librbd::cls_client::set_features(&op, m_new_features, m_features_mask);
348
349 using klass = EnableFeaturesRequest<I>;
350 librados::AioCompletion *comp =
351 create_rados_callback<klass, &klass::handle_set_features>(this);
352 int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, comp, &op);
11fdf7f2 353 ceph_assert(r == 0);
7c673cae
FG
354 comp->release();
355}
356
357template <typename I>
358Context *EnableFeaturesRequest<I>::handle_set_features(int *result) {
359 I &image_ctx = this->m_image_ctx;
360 CephContext *cct = image_ctx.cct;
361 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
362
363 if (*result < 0) {
364 lderr(cct) << "failed to update features: " << cpp_strerror(*result)
365 << dendl;
366 return handle_finish(*result);
367 }
368
369 send_create_object_map();
370 return nullptr;
371}
372
373template <typename I>
374void EnableFeaturesRequest<I>::send_create_object_map() {
375 I &image_ctx = this->m_image_ctx;
376 CephContext *cct = image_ctx.cct;
377
378 if (((image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0) ||
379 ((m_features & RBD_FEATURE_OBJECT_MAP) == 0)) {
380 send_enable_mirror_image();
381 return;
382 }
383
384 ldout(cct, 20) << this << " " << __func__ << dendl;
385
386 Context *ctx = create_context_callback<
387 EnableFeaturesRequest<I>,
388 &EnableFeaturesRequest<I>::handle_create_object_map>(this);
389
390 object_map::CreateRequest<I> *req =
391 object_map::CreateRequest<I>::create(&image_ctx, ctx);
392 req->send();
393}
394
395template <typename I>
396Context *EnableFeaturesRequest<I>::handle_create_object_map(int *result) {
397 I &image_ctx = this->m_image_ctx;
398 CephContext *cct = image_ctx.cct;
399 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
400
401 if (*result < 0) {
402 lderr(cct) << "failed to create object map: " << cpp_strerror(*result)
403 << dendl;
404 return handle_finish(*result);
405 }
406
407 send_enable_mirror_image();
408 return nullptr;
409}
410
411template <typename I>
412void EnableFeaturesRequest<I>::send_enable_mirror_image() {
413 I &image_ctx = this->m_image_ctx;
414 CephContext *cct = image_ctx.cct;
7c673cae
FG
415
416 if (!m_enable_mirroring) {
417 send_notify_update();
418 return;
419 }
420
9f95a23c
TL
421 ldout(cct, 20) << this << " " << __func__ << dendl;
422
7c673cae
FG
423 Context *ctx = create_context_callback<
424 EnableFeaturesRequest<I>,
425 &EnableFeaturesRequest<I>::handle_enable_mirror_image>(this);
426
1911f103
TL
427 auto req = mirror::EnableRequest<I>::create(
428 &image_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "", false, ctx);
7c673cae
FG
429 req->send();
430}
431
432template <typename I>
433Context *EnableFeaturesRequest<I>::handle_enable_mirror_image(int *result) {
434 I &image_ctx = this->m_image_ctx;
435 CephContext *cct = image_ctx.cct;
436 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
437
438 if (*result < 0) {
439 lderr(cct) << "failed to enable mirroring: " << cpp_strerror(*result)
440 << dendl;
441 // not fatal
442 }
443
444 send_notify_update();
445 return nullptr;
446}
447
448template <typename I>
449void EnableFeaturesRequest<I>::send_notify_update() {
450 I &image_ctx = this->m_image_ctx;
451 CephContext *cct = image_ctx.cct;
452 ldout(cct, 20) << this << " " << __func__ << dendl;
453
454 Context *ctx = create_context_callback<
455 EnableFeaturesRequest<I>,
456 &EnableFeaturesRequest<I>::handle_notify_update>(this);
457
458 image_ctx.notify_update(ctx);
459}
460
461template <typename I>
462Context *EnableFeaturesRequest<I>::handle_notify_update(int *result) {
463 I &image_ctx = this->m_image_ctx;
464 CephContext *cct = image_ctx.cct;
465 ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl;
466
467 return handle_finish(*result);
468}
469
470template <typename I>
471Context *EnableFeaturesRequest<I>::handle_finish(int r) {
472 I &image_ctx = this->m_image_ctx;
473 CephContext *cct = image_ctx.cct;
474 ldout(cct, 20) << this << " " << __func__ << ": r=" << r << dendl;
475
476 {
9f95a23c 477 std::unique_lock locker{image_ctx.owner_lock};
7c673cae
FG
478
479 if (image_ctx.exclusive_lock != nullptr && m_requests_blocked) {
480 image_ctx.exclusive_lock->unblock_requests();
481 }
482 if (m_writes_blocked) {
f67539c2 483 image_ctx.io_image_dispatcher->unblock_writes();
7c673cae
FG
484 }
485 }
486 image_ctx.state->handle_prepare_lock_complete();
487
488 return this->create_context_finisher(r);
489}
490
491} // namespace operation
492} // namespace librbd
493
494template class librbd::operation::EnableFeaturesRequest<librbd::ImageCtx>;