]>
Commit | Line | Data |
---|---|---|
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 | ||
23 | namespace librbd { | |
24 | namespace operation { | |
25 | ||
26 | using util::create_async_context_callback; | |
27 | using util::create_context_callback; | |
28 | using util::create_rados_callback; | |
29 | ||
30 | template <typename I> | |
31 | EnableFeaturesRequest<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 | ||
38 | template <typename I> | |
39 | void 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 | ||
49 | template <typename I> | |
50 | bool 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 | ||
61 | template <typename I> | |
62 | void 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 | ||
73 | template <typename I> | |
74 | Context *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 | ||
88 | template <typename I> | |
89 | void 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 | ||
100 | template <typename I> | |
101 | Context *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 | ||
116 | template <typename I> | |
117 | void 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 | ||
143 | template <typename I> | |
144 | Context *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 | ||
227 | template <typename I> | |
228 | void 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 | ||
253 | template <typename I> | |
254 | Context *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 | ||
269 | template <typename I> | |
270 | void 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 | ||
283 | template <typename I> | |
284 | Context *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 | ||
299 | template <typename I> | |
300 | void 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 | ||
322 | template <typename I> | |
323 | Context *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 | ||
338 | template <typename I> | |
339 | void 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 | ||
357 | template <typename I> | |
358 | Context *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 | ||
373 | template <typename I> | |
374 | void 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 | ||
395 | template <typename I> | |
396 | Context *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 | ||
411 | template <typename I> | |
412 | void 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 | ||
432 | template <typename I> | |
433 | Context *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 | ||
448 | template <typename I> | |
449 | void 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 | ||
461 | template <typename I> | |
462 | Context *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 | ||
470 | template <typename I> | |
471 | Context *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 | ||
494 | template class librbd::operation::EnableFeaturesRequest<librbd::ImageCtx>; |