]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/operation/EnableFeaturesRequest.cc
import 15.2.0 Octopus source
[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"
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"
17
18#define dout_subsys ceph_subsys_rbd
19#undef dout_prefix
20#define dout_prefix *_dout << "librbd::EnableFeaturesRequest: "
21
22namespace librbd {
23namespace operation {
24
25using util::create_async_context_callback;
26using util::create_context_callback;
27using util::create_rados_callback;
28
29template <typename I>
30EnableFeaturesRequest<I>::EnableFeaturesRequest(I &image_ctx,
31 Context *on_finish,
32 uint64_t journal_op_tid,
33 uint64_t features)
34 : Request<I>(image_ctx, on_finish, journal_op_tid), m_features(features) {
35}
36
37template <typename I>
38void EnableFeaturesRequest<I>::send_op() {
39 I &image_ctx = this->m_image_ctx;
40 CephContext *cct = image_ctx.cct;
9f95a23c 41 ceph_assert(ceph_mutex_is_locked(image_ctx.owner_lock));
7c673cae
FG
42
43 ldout(cct, 20) << this << " " << __func__ << ": features=" << m_features
44 << dendl;
45 send_prepare_lock();
46}
47
48template <typename I>
49bool EnableFeaturesRequest<I>::should_complete(int r) {
50 I &image_ctx = this->m_image_ctx;
51 CephContext *cct = image_ctx.cct;
11fdf7f2 52 ldout(cct, 20) << this << " " << __func__ << " r=" << r << dendl;
7c673cae
FG
53
54 if (r < 0) {
55 lderr(cct) << "encountered error: " << cpp_strerror(r) << dendl;
56 }
57 return true;
58}
59
60template <typename I>
61void 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;
65
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)));
70}
71
72template <typename I>
73Context *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;
77
78 if (*result < 0) {
79 lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl;
80 return this->create_context_finisher(*result);
81 }
82
83 send_block_writes();
84 return nullptr;
85}
86
87template <typename I>
88void 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;
92
9f95a23c 93 std::unique_lock locker{image_ctx.owner_lock};
7c673cae
FG
94 image_ctx.io_work_queue->block_writes(create_context_callback<
95 EnableFeaturesRequest<I>,
96 &EnableFeaturesRequest<I>::handle_block_writes>(this));
97}
98
99template <typename I>
100Context *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;
104
105 if (*result < 0) {
106 lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl;
107 return handle_finish(*result);
108 }
109 m_writes_blocked = true;
110
111 send_get_mirror_mode();
112 return nullptr;
113}
114
115template <typename I>
116void EnableFeaturesRequest<I>::send_get_mirror_mode() {
117 I &image_ctx = this->m_image_ctx;
118 CephContext *cct = image_ctx.cct;
119
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);
125 return;
126 }
127
128 ldout(cct, 20) << this << " " << __func__ << dendl;
129
130 librados::ObjectReadOperation op;
131 cls_client::mirror_mode_get_start(&op);
132
133 using klass = EnableFeaturesRequest<I>;
134 librados::AioCompletion *comp =
135 create_rados_callback<klass, &klass::handle_get_mirror_mode>(this);
136 m_out_bl.clear();
137 int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
11fdf7f2 138 ceph_assert(r == 0);
7c673cae
FG
139 comp->release();
140}
141
142template <typename I>
143Context *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;
147
148 cls::rbd::MirrorMode mirror_mode = cls::rbd::MIRROR_MODE_DISABLED;
149 if (*result == 0) {
11fdf7f2 150 auto it = m_out_bl.cbegin();
7c673cae
FG
151 *result = cls_client::mirror_mode_get_finish(&it, &mirror_mode);
152 } else if (*result == -ENOENT) {
153 *result = 0;
154 }
155
156 if (*result < 0) {
157 lderr(cct) << "failed to retrieve pool mirror mode: "
158 << cpp_strerror(*result) << dendl;
159 return handle_finish(*result);
160 }
161
162 m_enable_mirroring = (mirror_mode == cls::rbd::MIRROR_MODE_POOL);
163
164 bool create_journal = false;
165 do {
9f95a23c 166 std::unique_lock locker{image_ctx.owner_lock};
7c673cae
FG
167
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;
175 }
176
177 m_features &= ~image_ctx.features;
81eedcae
TL
178
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);
183 }
184
7c673cae
FG
185 m_new_features = image_ctx.features | m_features;
186 m_features_mask = m_features;
187
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;
192 *result = -EINVAL;
193 break;
194 }
195 m_enable_flags |= RBD_FLAG_OBJECT_MAP_INVALID;
81eedcae 196 m_features_mask |= (RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_FAST_DIFF);
7c673cae
FG
197 }
198 if ((m_features & RBD_FEATURE_FAST_DIFF) != 0) {
7c673cae 199 m_enable_flags |= RBD_FLAG_FAST_DIFF_INVALID;
81eedcae 200 m_features_mask |= (RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_OBJECT_MAP);
7c673cae 201 }
81eedcae 202
7c673cae
FG
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;
207 *result = -EINVAL;
208 break;
209 }
210 m_features_mask |= RBD_FEATURE_EXCLUSIVE_LOCK;
211 create_journal = true;
212 }
213 } while (false);
214
215 if (*result < 0) {
216 return handle_finish(*result);
217 }
218 if (create_journal) {
219 send_create_journal();
220 return nullptr;
221 }
222 send_append_op_event();
223 return nullptr;
224}
225
226template <typename I>
227void EnableFeaturesRequest<I>::send_create_journal() {
228 I &image_ctx = this->m_image_ctx;
229 CephContext *cct = image_ctx.cct;
230
231 ldout(cct, 20) << this << " " << __func__ << dendl;
232
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);
237
238 journal::CreateRequest<I> *req = journal::CreateRequest<I>::create(
11fdf7f2
TL
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"),
7c673cae
FG
243 cls::journal::Tag::TAG_CLASS_NEW, tag_data,
244 librbd::Journal<>::IMAGE_CLIENT_ID, image_ctx.op_work_queue, ctx);
245
246 req->send();
247}
248
249template <typename I>
250Context *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;
254
255 if (*result < 0) {
256 lderr(cct) << "failed to create journal: " << cpp_strerror(*result)
257 << dendl;
258 return handle_finish(*result);
259 }
260
261 send_append_op_event();
262 return nullptr;
263}
264
265template <typename I>
266void EnableFeaturesRequest<I>::send_append_op_event() {
267 I &image_ctx = this->m_image_ctx;
268 CephContext *cct = image_ctx.cct;
269
270 if (!this->template append_op_event<
271 EnableFeaturesRequest<I>,
272 &EnableFeaturesRequest<I>::handle_append_op_event>(this)) {
273 send_update_flags();
274 }
275
276 ldout(cct, 20) << this << " " << __func__ << dendl;
277}
278
279template <typename I>
280Context *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;
284
285 if (*result < 0) {
286 lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result)
287 << dendl;
288 return handle_finish(*result);
289 }
290
291 send_update_flags();
292 return nullptr;
293}
294
295template <typename I>
296void EnableFeaturesRequest<I>::send_update_flags() {
297 I &image_ctx = this->m_image_ctx;
298 CephContext *cct = image_ctx.cct;
299
300 if (m_enable_flags == 0) {
301 send_set_features();
302 return;
303 }
304
305 ldout(cct, 20) << this << " " << __func__ << ": enable_flags="
306 << m_enable_flags << dendl;
307
308 Context *ctx = create_context_callback<
309 EnableFeaturesRequest<I>,
310 &EnableFeaturesRequest<I>::handle_update_flags>(this);
311
312 image::SetFlagsRequest<I> *req =
313 image::SetFlagsRequest<I>::create(&image_ctx, m_enable_flags,
314 m_enable_flags, ctx);
315 req->send();
316}
317
318template <typename I>
319Context *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;
323
324 if (*result < 0) {
325 lderr(cct) << "failed to update image flags: " << cpp_strerror(*result)
326 << dendl;
327 return handle_finish(*result);
328 }
329
330 send_set_features();
331 return nullptr;
332}
333
334template <typename I>
335void 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
340 << dendl;
341
342 librados::ObjectWriteOperation op;
343 librbd::cls_client::set_features(&op, m_new_features, m_features_mask);
344
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);
11fdf7f2 349 ceph_assert(r == 0);
7c673cae
FG
350 comp->release();
351}
352
353template <typename I>
354Context *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;
358
359 if (*result < 0) {
360 lderr(cct) << "failed to update features: " << cpp_strerror(*result)
361 << dendl;
362 return handle_finish(*result);
363 }
364
365 send_create_object_map();
366 return nullptr;
367}
368
369template <typename I>
370void EnableFeaturesRequest<I>::send_create_object_map() {
371 I &image_ctx = this->m_image_ctx;
372 CephContext *cct = image_ctx.cct;
373
374 if (((image_ctx.features & RBD_FEATURE_OBJECT_MAP) != 0) ||
375 ((m_features & RBD_FEATURE_OBJECT_MAP) == 0)) {
376 send_enable_mirror_image();
377 return;
378 }
379
380 ldout(cct, 20) << this << " " << __func__ << dendl;
381
382 Context *ctx = create_context_callback<
383 EnableFeaturesRequest<I>,
384 &EnableFeaturesRequest<I>::handle_create_object_map>(this);
385
386 object_map::CreateRequest<I> *req =
387 object_map::CreateRequest<I>::create(&image_ctx, ctx);
388 req->send();
389}
390
391template <typename I>
392Context *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;
396
397 if (*result < 0) {
398 lderr(cct) << "failed to create object map: " << cpp_strerror(*result)
399 << dendl;
400 return handle_finish(*result);
401 }
402
403 send_enable_mirror_image();
404 return nullptr;
405}
406
407template <typename I>
408void EnableFeaturesRequest<I>::send_enable_mirror_image() {
409 I &image_ctx = this->m_image_ctx;
410 CephContext *cct = image_ctx.cct;
7c673cae
FG
411
412 if (!m_enable_mirroring) {
413 send_notify_update();
414 return;
415 }
416
9f95a23c
TL
417 ldout(cct, 20) << this << " " << __func__ << dendl;
418
7c673cae
FG
419 Context *ctx = create_context_callback<
420 EnableFeaturesRequest<I>,
421 &EnableFeaturesRequest<I>::handle_enable_mirror_image>(this);
422
9f95a23c
TL
423 mirror::EnableRequest<I> *req = mirror::EnableRequest<I>::create(
424 &image_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, ctx);
7c673cae
FG
425 req->send();
426}
427
428template <typename I>
429Context *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;
433
434 if (*result < 0) {
435 lderr(cct) << "failed to enable mirroring: " << cpp_strerror(*result)
436 << dendl;
437 // not fatal
438 }
439
440 send_notify_update();
441 return nullptr;
442}
443
444template <typename I>
445void 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;
449
450 Context *ctx = create_context_callback<
451 EnableFeaturesRequest<I>,
452 &EnableFeaturesRequest<I>::handle_notify_update>(this);
453
454 image_ctx.notify_update(ctx);
455}
456
457template <typename I>
458Context *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;
462
463 return handle_finish(*result);
464}
465
466template <typename I>
467Context *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;
471
472 {
9f95a23c 473 std::unique_lock locker{image_ctx.owner_lock};
7c673cae
FG
474
475 if (image_ctx.exclusive_lock != nullptr && m_requests_blocked) {
476 image_ctx.exclusive_lock->unblock_requests();
477 }
478 if (m_writes_blocked) {
479 image_ctx.io_work_queue->unblock_writes();
480 }
481 }
482 image_ctx.state->handle_prepare_lock_complete();
483
484 return this->create_context_finisher(r);
485}
486
487} // namespace operation
488} // namespace librbd
489
490template class librbd::operation::EnableFeaturesRequest<librbd::ImageCtx>;