]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/operation/EnableFeaturesRequest.cc
import 15.2.2 octopus source
[ceph.git] / ceph / src / librbd / operation / EnableFeaturesRequest.cc
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
22 namespace librbd {
23 namespace operation {
24
25 using util::create_async_context_callback;
26 using util::create_context_callback;
27 using util::create_rados_callback;
28
29 template <typename I>
30 EnableFeaturesRequest<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
37 template <typename I>
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));
42
43 ldout(cct, 20) << this << " " << __func__ << ": features=" << m_features
44 << dendl;
45 send_prepare_lock();
46 }
47
48 template <typename I>
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;
53
54 if (r < 0) {
55 lderr(cct) << "encountered error: " << cpp_strerror(r) << dendl;
56 }
57 return true;
58 }
59
60 template <typename I>
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;
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
72 template <typename I>
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;
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
87 template <typename I>
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;
92
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));
97 }
98
99 template <typename I>
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;
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
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;
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);
138 ceph_assert(r == 0);
139 comp->release();
140 }
141
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;
147
148 cls::rbd::MirrorMode mirror_mode = cls::rbd::MIRROR_MODE_DISABLED;
149 if (*result == 0) {
150 auto it = m_out_bl.cbegin();
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 {
166 std::unique_lock locker{image_ctx.owner_lock};
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;
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
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;
196 m_features_mask |= (RBD_FEATURE_EXCLUSIVE_LOCK | RBD_FEATURE_FAST_DIFF);
197 }
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);
201 }
202
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
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;
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(
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);
245
246 req->send();
247 }
248
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;
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
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;
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
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;
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
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;
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
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;
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
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
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);
349 ceph_assert(r == 0);
350 comp->release();
351 }
352
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;
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
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;
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
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;
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
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;
411
412 if (!m_enable_mirroring) {
413 send_notify_update();
414 return;
415 }
416
417 ldout(cct, 20) << this << " " << __func__ << dendl;
418
419 Context *ctx = create_context_callback<
420 EnableFeaturesRequest<I>,
421 &EnableFeaturesRequest<I>::handle_enable_mirror_image>(this);
422
423 auto req = mirror::EnableRequest<I>::create(
424 &image_ctx, cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "", false, ctx);
425 req->send();
426 }
427
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;
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
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;
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
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;
462
463 return handle_finish(*result);
464 }
465
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;
471
472 {
473 std::unique_lock locker{image_ctx.owner_lock};
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
490 template class librbd::operation::EnableFeaturesRequest<librbd::ImageCtx>;