]>
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/DisableFeaturesRequest.h" | |
5 | #include "common/dout.h" | |
6 | #include "common/errno.h" | |
7 | #include "cls/rbd/cls_rbd_client.h" | |
8 | #include "librbd/ExclusiveLock.h" | |
9 | #include "librbd/ImageCtx.h" | |
10 | #include "librbd/ImageState.h" | |
11 | #include "librbd/Journal.h" | |
12 | #include "librbd/Utils.h" | |
13 | #include "librbd/image/SetFlagsRequest.h" | |
14 | #include "librbd/io/ImageRequestWQ.h" | |
15 | #include "librbd/journal/RemoveRequest.h" | |
16 | #include "librbd/mirror/DisableRequest.h" | |
17 | #include "librbd/object_map/RemoveRequest.h" | |
18 | ||
19 | #define dout_subsys ceph_subsys_rbd | |
20 | #undef dout_prefix | |
21 | #define dout_prefix *_dout << "librbd::DisableFeaturesRequest: " | |
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 | DisableFeaturesRequest<I>::DisableFeaturesRequest(I &image_ctx, | |
32 | Context *on_finish, | |
33 | uint64_t journal_op_tid, | |
34 | uint64_t features, | |
35 | bool force) | |
36 | : Request<I>(image_ctx, on_finish, journal_op_tid), m_features(features), | |
37 | m_force(force) { | |
38 | } | |
39 | ||
40 | template <typename I> | |
41 | void DisableFeaturesRequest<I>::send_op() { | |
42 | I &image_ctx = this->m_image_ctx; | |
43 | CephContext *cct = image_ctx.cct; | |
44 | assert(image_ctx.owner_lock.is_locked()); | |
45 | ||
46 | ldout(cct, 20) << this << " " << __func__ << ": features=" << m_features | |
47 | << dendl; | |
48 | ||
49 | send_prepare_lock(); | |
50 | } | |
51 | ||
52 | template <typename I> | |
53 | bool DisableFeaturesRequest<I>::should_complete(int r) { | |
54 | I &image_ctx = this->m_image_ctx; | |
55 | CephContext *cct = image_ctx.cct; | |
56 | ldout(cct, 20) << this << " " << __func__ << "r=" << r << dendl; | |
57 | ||
58 | if (r < 0) { | |
59 | lderr(cct) << "encountered error: " << cpp_strerror(r) << dendl; | |
60 | } | |
61 | return true; | |
62 | } | |
63 | ||
64 | template <typename I> | |
65 | void DisableFeaturesRequest<I>::send_prepare_lock() { | |
66 | I &image_ctx = this->m_image_ctx; | |
67 | CephContext *cct = image_ctx.cct; | |
68 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
69 | ||
70 | image_ctx.state->prepare_lock(create_async_context_callback( | |
71 | image_ctx, create_context_callback< | |
72 | DisableFeaturesRequest<I>, | |
73 | &DisableFeaturesRequest<I>::handle_prepare_lock>(this))); | |
74 | } | |
75 | ||
76 | template <typename I> | |
77 | Context *DisableFeaturesRequest<I>::handle_prepare_lock(int *result) { | |
78 | I &image_ctx = this->m_image_ctx; | |
79 | CephContext *cct = image_ctx.cct; | |
80 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
81 | ||
82 | if (*result < 0) { | |
83 | lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl; | |
84 | return this->create_context_finisher(*result); | |
85 | } | |
86 | ||
87 | send_block_writes(); | |
88 | return nullptr; | |
89 | } | |
90 | ||
91 | template <typename I> | |
92 | void DisableFeaturesRequest<I>::send_block_writes() { | |
93 | I &image_ctx = this->m_image_ctx; | |
94 | CephContext *cct = image_ctx.cct; | |
95 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
96 | ||
97 | RWLock::WLocker locker(image_ctx.owner_lock); | |
98 | image_ctx.io_work_queue->block_writes(create_context_callback< | |
99 | DisableFeaturesRequest<I>, | |
100 | &DisableFeaturesRequest<I>::handle_block_writes>(this)); | |
101 | } | |
102 | ||
103 | template <typename I> | |
104 | Context *DisableFeaturesRequest<I>::handle_block_writes(int *result) { | |
105 | I &image_ctx = this->m_image_ctx; | |
106 | CephContext *cct = image_ctx.cct; | |
107 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
108 | ||
109 | if (*result < 0) { | |
110 | lderr(cct) << "failed to block writes: " << cpp_strerror(*result) << dendl; | |
111 | return handle_finish(*result); | |
112 | } | |
113 | m_writes_blocked = true; | |
114 | ||
115 | { | |
116 | RWLock::WLocker locker(image_ctx.owner_lock); | |
117 | // avoid accepting new requests from peers while we manipulate | |
118 | // the image features | |
119 | if (image_ctx.exclusive_lock != nullptr && | |
120 | (image_ctx.journal == nullptr || | |
121 | !image_ctx.journal->is_journal_replaying())) { | |
122 | image_ctx.exclusive_lock->block_requests(0); | |
123 | m_requests_blocked = true; | |
124 | } | |
125 | } | |
126 | ||
127 | send_acquire_exclusive_lock(); | |
128 | return nullptr; | |
129 | } | |
130 | ||
131 | template <typename I> | |
132 | void DisableFeaturesRequest<I>::send_acquire_exclusive_lock() { | |
133 | I &image_ctx = this->m_image_ctx; | |
134 | CephContext *cct = image_ctx.cct; | |
135 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
136 | ||
137 | Context *ctx = create_context_callback< | |
138 | DisableFeaturesRequest<I>, | |
139 | &DisableFeaturesRequest<I>::handle_acquire_exclusive_lock>(this); | |
140 | ||
141 | { | |
142 | RWLock::WLocker locker(image_ctx.owner_lock); | |
143 | // if disabling features w/ exclusive lock supported, we need to | |
144 | // acquire the lock to temporarily block IO against the image | |
145 | if (image_ctx.exclusive_lock != nullptr && | |
146 | !image_ctx.exclusive_lock->is_lock_owner()) { | |
147 | m_acquired_lock = true; | |
148 | ||
149 | image_ctx.exclusive_lock->acquire_lock(ctx); | |
150 | return; | |
151 | } | |
152 | } | |
153 | ||
154 | ctx->complete(0); | |
155 | } | |
156 | ||
157 | template <typename I> | |
158 | Context *DisableFeaturesRequest<I>::handle_acquire_exclusive_lock(int *result) { | |
159 | I &image_ctx = this->m_image_ctx; | |
160 | CephContext *cct = image_ctx.cct; | |
161 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
162 | ||
163 | if (*result < 0) { | |
164 | lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl; | |
165 | return handle_finish(*result); | |
166 | } else if (m_acquired_lock && (image_ctx.exclusive_lock == nullptr || | |
167 | !image_ctx.exclusive_lock->is_lock_owner())) { | |
168 | lderr(cct) << "failed to acquire exclusive lock" << dendl; | |
169 | *result = -EROFS; | |
170 | return handle_finish(*result); | |
171 | } | |
172 | ||
173 | do { | |
174 | RWLock::WLocker locker(image_ctx.owner_lock); | |
175 | ||
176 | m_features &= image_ctx.features; | |
177 | m_new_features = image_ctx.features & ~m_features; | |
178 | m_features_mask = m_features; | |
179 | ||
180 | if ((m_features & RBD_FEATURE_EXCLUSIVE_LOCK) != 0) { | |
181 | if ((m_new_features & RBD_FEATURE_OBJECT_MAP) != 0 || | |
182 | (m_new_features & RBD_FEATURE_JOURNALING) != 0) { | |
183 | lderr(cct) << "cannot disable exclusive-lock. object-map " | |
184 | "or journaling must be disabled before " | |
185 | "disabling exclusive-lock." << dendl; | |
186 | *result = -EINVAL; | |
187 | break; | |
188 | } | |
189 | m_features_mask |= (RBD_FEATURE_OBJECT_MAP | | |
190 | RBD_FEATURE_JOURNALING); | |
191 | } | |
192 | if ((m_features & RBD_FEATURE_FAST_DIFF) != 0) { | |
193 | m_disable_flags |= RBD_FLAG_FAST_DIFF_INVALID; | |
194 | } | |
195 | if ((m_features & RBD_FEATURE_OBJECT_MAP) != 0) { | |
196 | if ((m_new_features & RBD_FEATURE_FAST_DIFF) != 0) { | |
197 | lderr(cct) << "cannot disable object-map. fast-diff must be " | |
198 | "disabled before disabling object-map." << dendl; | |
199 | *result = -EINVAL; | |
200 | break; | |
201 | } | |
202 | m_disable_flags |= RBD_FLAG_OBJECT_MAP_INVALID; | |
203 | } | |
204 | } while (false); | |
205 | ||
206 | if (*result < 0) { | |
207 | return handle_finish(*result); | |
208 | } | |
209 | ||
210 | send_get_mirror_mode(); | |
211 | return nullptr; | |
212 | } | |
213 | ||
214 | template <typename I> | |
215 | void DisableFeaturesRequest<I>::send_get_mirror_mode() { | |
216 | I &image_ctx = this->m_image_ctx; | |
217 | CephContext *cct = image_ctx.cct; | |
218 | ||
219 | if ((m_features & RBD_FEATURE_JOURNALING) == 0) { | |
220 | send_append_op_event(); | |
221 | return; | |
222 | } | |
223 | ||
224 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
225 | ||
226 | librados::ObjectReadOperation op; | |
227 | cls_client::mirror_mode_get_start(&op); | |
228 | ||
229 | using klass = DisableFeaturesRequest<I>; | |
230 | librados::AioCompletion *comp = | |
231 | create_rados_callback<klass, &klass::handle_get_mirror_mode>(this); | |
232 | m_out_bl.clear(); | |
233 | int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl); | |
234 | assert(r == 0); | |
235 | comp->release(); | |
236 | } | |
237 | ||
238 | template <typename I> | |
239 | Context *DisableFeaturesRequest<I>::handle_get_mirror_mode(int *result) { | |
240 | I &image_ctx = this->m_image_ctx; | |
241 | CephContext *cct = image_ctx.cct; | |
242 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
243 | ||
244 | if (*result == 0) { | |
245 | bufferlist::iterator it = m_out_bl.begin(); | |
246 | *result = cls_client::mirror_mode_get_finish(&it, &m_mirror_mode); | |
247 | } | |
248 | ||
249 | if (*result < 0 && *result != -ENOENT) { | |
250 | lderr(cct) << "failed to retrieve pool mirror mode: " | |
251 | << cpp_strerror(*result) << dendl; | |
252 | return handle_finish(*result); | |
253 | } | |
254 | ||
255 | ldout(cct, 20) << this << " " << __func__ << ": m_mirror_mode=" | |
256 | << m_mirror_mode << dendl; | |
257 | ||
258 | send_get_mirror_image(); | |
259 | return nullptr; | |
260 | } | |
261 | ||
262 | template <typename I> | |
263 | void DisableFeaturesRequest<I>::send_get_mirror_image() { | |
264 | I &image_ctx = this->m_image_ctx; | |
265 | CephContext *cct = image_ctx.cct; | |
266 | ||
267 | if (m_mirror_mode != cls::rbd::MIRROR_MODE_IMAGE) { | |
268 | send_disable_mirror_image(); | |
269 | return; | |
270 | } | |
271 | ||
272 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
273 | ||
274 | librados::ObjectReadOperation op; | |
275 | cls_client::mirror_image_get_start(&op, image_ctx.id); | |
276 | ||
277 | using klass = DisableFeaturesRequest<I>; | |
278 | librados::AioCompletion *comp = | |
279 | create_rados_callback<klass, &klass::handle_get_mirror_image>(this); | |
280 | m_out_bl.clear(); | |
281 | int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl); | |
282 | assert(r == 0); | |
283 | comp->release(); | |
284 | } | |
285 | ||
286 | template <typename I> | |
287 | Context *DisableFeaturesRequest<I>::handle_get_mirror_image(int *result) { | |
288 | I &image_ctx = this->m_image_ctx; | |
289 | CephContext *cct = image_ctx.cct; | |
290 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
291 | ||
292 | cls::rbd::MirrorImage mirror_image; | |
293 | ||
294 | if (*result == 0) { | |
295 | bufferlist::iterator it = m_out_bl.begin(); | |
296 | *result = cls_client::mirror_image_get_finish(&it, &mirror_image); | |
297 | } | |
298 | ||
299 | if (*result < 0 && *result != -ENOENT) { | |
300 | lderr(cct) << "failed to retrieve pool mirror image: " | |
301 | << cpp_strerror(*result) << dendl; | |
302 | return handle_finish(*result); | |
303 | } | |
304 | ||
305 | if ((mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) && !m_force) { | |
306 | lderr(cct) << "cannot disable journaling: image mirroring " | |
307 | << "enabled and mirror pool mode set to image" | |
308 | << dendl; | |
309 | *result = -EINVAL; | |
310 | return handle_finish(*result); | |
311 | } | |
312 | ||
313 | send_disable_mirror_image(); | |
314 | return nullptr; | |
315 | } | |
316 | ||
317 | template <typename I> | |
318 | void DisableFeaturesRequest<I>::send_disable_mirror_image() { | |
319 | I &image_ctx = this->m_image_ctx; | |
320 | CephContext *cct = image_ctx.cct; | |
321 | ||
322 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
323 | ||
324 | Context *ctx = create_context_callback< | |
325 | DisableFeaturesRequest<I>, | |
326 | &DisableFeaturesRequest<I>::handle_disable_mirror_image>(this); | |
327 | ||
328 | mirror::DisableRequest<I> *req = | |
329 | mirror::DisableRequest<I>::create(&image_ctx, m_force, true, ctx); | |
330 | req->send(); | |
331 | } | |
332 | ||
333 | template <typename I> | |
334 | Context *DisableFeaturesRequest<I>::handle_disable_mirror_image(int *result) { | |
335 | I &image_ctx = this->m_image_ctx; | |
336 | CephContext *cct = image_ctx.cct; | |
337 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
338 | ||
339 | if (*result < 0) { | |
340 | lderr(cct) << "failed to disable image mirroring: " << cpp_strerror(*result) | |
341 | << dendl; | |
342 | // not fatal | |
343 | } | |
344 | ||
345 | send_close_journal(); | |
346 | return nullptr; | |
347 | } | |
348 | ||
349 | template <typename I> | |
350 | void DisableFeaturesRequest<I>::send_close_journal() { | |
351 | I &image_ctx = this->m_image_ctx; | |
352 | CephContext *cct = image_ctx.cct; | |
353 | ||
354 | { | |
355 | RWLock::WLocker locker(image_ctx.owner_lock); | |
356 | if (image_ctx.journal != nullptr) { | |
7c673cae FG |
357 | ldout(cct, 20) << this << " " << __func__ << dendl; |
358 | ||
224ce89b | 359 | std::swap(m_journal, image_ctx.journal); |
7c673cae FG |
360 | Context *ctx = create_context_callback< |
361 | DisableFeaturesRequest<I>, | |
362 | &DisableFeaturesRequest<I>::handle_close_journal>(this); | |
363 | ||
224ce89b | 364 | m_journal->close(ctx); |
7c673cae FG |
365 | return; |
366 | } | |
367 | } | |
368 | ||
369 | send_remove_journal(); | |
370 | } | |
371 | ||
372 | template <typename I> | |
373 | Context *DisableFeaturesRequest<I>::handle_close_journal(int *result) { | |
374 | I &image_ctx = this->m_image_ctx; | |
375 | CephContext *cct = image_ctx.cct; | |
376 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
377 | ||
378 | if (*result < 0) { | |
379 | lderr(cct) << "failed to close image journal: " << cpp_strerror(*result) | |
380 | << dendl; | |
7c673cae FG |
381 | } |
382 | ||
224ce89b WB |
383 | assert(m_journal != nullptr); |
384 | delete m_journal; | |
385 | m_journal = nullptr; | |
386 | ||
7c673cae FG |
387 | send_remove_journal(); |
388 | return nullptr; | |
389 | } | |
390 | ||
391 | template <typename I> | |
392 | void DisableFeaturesRequest<I>::send_remove_journal() { | |
393 | I &image_ctx = this->m_image_ctx; | |
394 | CephContext *cct = image_ctx.cct; | |
395 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
396 | ||
397 | Context *ctx = create_context_callback< | |
398 | DisableFeaturesRequest<I>, | |
399 | &DisableFeaturesRequest<I>::handle_remove_journal>(this); | |
400 | ||
401 | journal::RemoveRequest<I> *req = journal::RemoveRequest<I>::create( | |
402 | image_ctx.md_ctx, image_ctx.id, librbd::Journal<>::IMAGE_CLIENT_ID, | |
403 | image_ctx.op_work_queue, ctx); | |
404 | ||
405 | req->send(); | |
406 | } | |
407 | ||
408 | template <typename I> | |
409 | Context *DisableFeaturesRequest<I>::handle_remove_journal(int *result) { | |
410 | I &image_ctx = this->m_image_ctx; | |
411 | CephContext *cct = image_ctx.cct; | |
412 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
413 | ||
414 | if (*result < 0) { | |
415 | lderr(cct) << "failed to remove image journal: " << cpp_strerror(*result) | |
416 | << dendl; | |
417 | return handle_finish(*result); | |
418 | } | |
419 | ||
420 | send_append_op_event(); | |
421 | return nullptr; | |
422 | } | |
423 | ||
424 | template <typename I> | |
425 | void DisableFeaturesRequest<I>::send_append_op_event() { | |
426 | I &image_ctx = this->m_image_ctx; | |
427 | CephContext *cct = image_ctx.cct; | |
428 | ||
429 | if (!this->template append_op_event< | |
430 | DisableFeaturesRequest<I>, | |
431 | &DisableFeaturesRequest<I>::handle_append_op_event>(this)) { | |
432 | send_remove_object_map(); | |
433 | } | |
434 | ||
435 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
436 | } | |
437 | ||
438 | template <typename I> | |
439 | Context *DisableFeaturesRequest<I>::handle_append_op_event(int *result) { | |
440 | I &image_ctx = this->m_image_ctx; | |
441 | CephContext *cct = image_ctx.cct; | |
442 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
443 | ||
444 | if (*result < 0) { | |
445 | lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result) | |
446 | << dendl; | |
447 | return handle_finish(*result); | |
448 | } | |
449 | ||
450 | send_remove_object_map(); | |
451 | return nullptr; | |
452 | } | |
453 | ||
454 | template <typename I> | |
455 | void DisableFeaturesRequest<I>::send_remove_object_map() { | |
456 | I &image_ctx = this->m_image_ctx; | |
457 | CephContext *cct = image_ctx.cct; | |
458 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
459 | ||
460 | if ((m_features & RBD_FEATURE_OBJECT_MAP) == 0) { | |
461 | send_set_features(); | |
462 | return; | |
463 | } | |
464 | ||
465 | Context *ctx = create_context_callback< | |
466 | DisableFeaturesRequest<I>, | |
467 | &DisableFeaturesRequest<I>::handle_remove_object_map>(this); | |
468 | ||
469 | object_map::RemoveRequest<I> *req = | |
470 | object_map::RemoveRequest<I>::create(&image_ctx, ctx); | |
471 | req->send(); | |
472 | } | |
473 | ||
474 | template <typename I> | |
475 | Context *DisableFeaturesRequest<I>::handle_remove_object_map(int *result) { | |
476 | I &image_ctx = this->m_image_ctx; | |
477 | CephContext *cct = image_ctx.cct; | |
478 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
479 | ||
480 | if (*result < 0) { | |
481 | lderr(cct) << "failed to remove object map: " << cpp_strerror(*result) << dendl; | |
482 | return handle_finish(*result); | |
483 | } | |
484 | ||
485 | send_set_features(); | |
486 | return nullptr; | |
487 | } | |
488 | ||
489 | template <typename I> | |
490 | void DisableFeaturesRequest<I>::send_set_features() { | |
491 | I &image_ctx = this->m_image_ctx; | |
492 | CephContext *cct = image_ctx.cct; | |
493 | ldout(cct, 20) << this << " " << __func__ << ": new_features=" | |
494 | << m_new_features << ", features_mask=" << m_features_mask | |
495 | << dendl; | |
496 | ||
497 | librados::ObjectWriteOperation op; | |
498 | librbd::cls_client::set_features(&op, m_new_features, m_features_mask); | |
499 | ||
500 | using klass = DisableFeaturesRequest<I>; | |
501 | librados::AioCompletion *comp = | |
502 | create_rados_callback<klass, &klass::handle_set_features>(this); | |
503 | int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, comp, &op); | |
504 | assert(r == 0); | |
505 | comp->release(); | |
506 | } | |
507 | ||
508 | template <typename I> | |
509 | Context *DisableFeaturesRequest<I>::handle_set_features(int *result) { | |
510 | I &image_ctx = this->m_image_ctx; | |
511 | CephContext *cct = image_ctx.cct; | |
512 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
513 | ||
514 | if (*result == -EINVAL && (m_features_mask & RBD_FEATURE_JOURNALING) != 0) { | |
515 | // NOTE: infernalis OSDs will not accept a mask with new features, so | |
516 | // re-attempt with a reduced mask. | |
517 | ldout(cct, 5) << this << " " << __func__ | |
518 | << ": re-attempt with a reduced mask" << dendl; | |
519 | m_features_mask &= ~RBD_FEATURE_JOURNALING; | |
520 | send_set_features(); | |
521 | } | |
522 | ||
523 | if (*result < 0) { | |
524 | lderr(cct) << "failed to update features: " << cpp_strerror(*result) | |
525 | << dendl; | |
526 | return handle_finish(*result); | |
527 | } | |
528 | ||
529 | send_update_flags(); | |
530 | return nullptr; | |
531 | } | |
532 | ||
533 | template <typename I> | |
534 | void DisableFeaturesRequest<I>::send_update_flags() { | |
535 | I &image_ctx = this->m_image_ctx; | |
536 | CephContext *cct = image_ctx.cct; | |
537 | ||
538 | if (m_disable_flags == 0) { | |
539 | send_notify_update(); | |
540 | return; | |
541 | } | |
542 | ||
543 | ldout(cct, 20) << this << " " << __func__ << ": disable_flags=" | |
544 | << m_disable_flags << dendl; | |
545 | ||
546 | Context *ctx = create_context_callback< | |
547 | DisableFeaturesRequest<I>, | |
548 | &DisableFeaturesRequest<I>::handle_update_flags>(this); | |
549 | ||
550 | image::SetFlagsRequest<I> *req = | |
551 | image::SetFlagsRequest<I>::create(&image_ctx, 0, m_disable_flags, ctx); | |
552 | req->send(); | |
553 | } | |
554 | ||
555 | template <typename I> | |
556 | Context *DisableFeaturesRequest<I>::handle_update_flags(int *result) { | |
557 | I &image_ctx = this->m_image_ctx; | |
558 | CephContext *cct = image_ctx.cct; | |
559 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
560 | ||
561 | if (*result < 0) { | |
562 | lderr(cct) << "failed to update image flags: " << cpp_strerror(*result) | |
563 | << dendl; | |
564 | return handle_finish(*result); | |
565 | } | |
566 | ||
567 | send_notify_update(); | |
568 | return nullptr; | |
569 | } | |
570 | ||
571 | template <typename I> | |
572 | void DisableFeaturesRequest<I>::send_notify_update() { | |
573 | I &image_ctx = this->m_image_ctx; | |
574 | CephContext *cct = image_ctx.cct; | |
575 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
576 | ||
577 | Context *ctx = create_context_callback< | |
578 | DisableFeaturesRequest<I>, | |
579 | &DisableFeaturesRequest<I>::handle_notify_update>(this); | |
580 | ||
581 | image_ctx.notify_update(ctx); | |
582 | } | |
583 | ||
584 | template <typename I> | |
585 | Context *DisableFeaturesRequest<I>::handle_notify_update(int *result) { | |
586 | I &image_ctx = this->m_image_ctx; | |
587 | CephContext *cct = image_ctx.cct; | |
588 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
589 | ||
590 | if (image_ctx.exclusive_lock == nullptr || !m_acquired_lock) { | |
591 | return handle_finish(*result); | |
592 | } | |
593 | ||
594 | send_release_exclusive_lock(); | |
595 | return nullptr; | |
596 | } | |
597 | ||
598 | template <typename I> | |
599 | void DisableFeaturesRequest<I>::send_release_exclusive_lock() { | |
600 | I &image_ctx = this->m_image_ctx; | |
601 | CephContext *cct = image_ctx.cct; | |
602 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
603 | ||
604 | Context *ctx = create_context_callback< | |
605 | DisableFeaturesRequest<I>, | |
606 | &DisableFeaturesRequest<I>::handle_release_exclusive_lock>(this); | |
607 | ||
608 | image_ctx.exclusive_lock->release_lock(ctx); | |
609 | } | |
610 | ||
611 | template <typename I> | |
612 | Context *DisableFeaturesRequest<I>::handle_release_exclusive_lock(int *result) { | |
613 | I &image_ctx = this->m_image_ctx; | |
614 | CephContext *cct = image_ctx.cct; | |
615 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
616 | ||
617 | return handle_finish(*result); | |
618 | } | |
619 | ||
620 | template <typename I> | |
621 | Context *DisableFeaturesRequest<I>::handle_finish(int r) { | |
622 | I &image_ctx = this->m_image_ctx; | |
623 | CephContext *cct = image_ctx.cct; | |
624 | ldout(cct, 20) << this << " " << __func__ << ": r=" << r << dendl; | |
625 | ||
626 | { | |
627 | RWLock::WLocker locker(image_ctx.owner_lock); | |
628 | if (image_ctx.exclusive_lock != nullptr && m_requests_blocked) { | |
629 | image_ctx.exclusive_lock->unblock_requests(); | |
630 | } | |
631 | ||
632 | image_ctx.io_work_queue->unblock_writes(); | |
633 | } | |
634 | image_ctx.state->handle_prepare_lock_complete(); | |
635 | ||
636 | return this->create_context_finisher(r); | |
637 | } | |
638 | ||
639 | } // namespace operation | |
640 | } // namespace librbd | |
641 | ||
642 | template class librbd::operation::DisableFeaturesRequest<librbd::ImageCtx>; |