]>
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" | |
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; | |
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 | ||
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; | |
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 | ||
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 | ||
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 | ||
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); | |
11fdf7f2 | 138 | ceph_assert(r == 0); |
7c673cae FG |
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) { | |
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 | ||
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( | |
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 | ||
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); | |
11fdf7f2 | 349 | ceph_assert(r == 0); |
7c673cae FG |
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; | |
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 | ||
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 | { | |
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 | ||
490 | template class librbd::operation::EnableFeaturesRequest<librbd::ImageCtx>; |