]>
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) { | |
357 | ||
358 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
359 | ||
360 | Context *ctx = create_context_callback< | |
361 | DisableFeaturesRequest<I>, | |
362 | &DisableFeaturesRequest<I>::handle_close_journal>(this); | |
363 | ||
364 | image_ctx.journal->close(ctx); | |
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; | |
381 | return handle_finish(*result); | |
382 | } | |
383 | ||
384 | send_remove_journal(); | |
385 | return nullptr; | |
386 | } | |
387 | ||
388 | template <typename I> | |
389 | void DisableFeaturesRequest<I>::send_remove_journal() { | |
390 | I &image_ctx = this->m_image_ctx; | |
391 | CephContext *cct = image_ctx.cct; | |
392 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
393 | ||
394 | Context *ctx = create_context_callback< | |
395 | DisableFeaturesRequest<I>, | |
396 | &DisableFeaturesRequest<I>::handle_remove_journal>(this); | |
397 | ||
398 | journal::RemoveRequest<I> *req = journal::RemoveRequest<I>::create( | |
399 | image_ctx.md_ctx, image_ctx.id, librbd::Journal<>::IMAGE_CLIENT_ID, | |
400 | image_ctx.op_work_queue, ctx); | |
401 | ||
402 | req->send(); | |
403 | } | |
404 | ||
405 | template <typename I> | |
406 | Context *DisableFeaturesRequest<I>::handle_remove_journal(int *result) { | |
407 | I &image_ctx = this->m_image_ctx; | |
408 | CephContext *cct = image_ctx.cct; | |
409 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
410 | ||
411 | if (*result < 0) { | |
412 | lderr(cct) << "failed to remove image journal: " << cpp_strerror(*result) | |
413 | << dendl; | |
414 | return handle_finish(*result); | |
415 | } | |
416 | ||
417 | send_append_op_event(); | |
418 | return nullptr; | |
419 | } | |
420 | ||
421 | template <typename I> | |
422 | void DisableFeaturesRequest<I>::send_append_op_event() { | |
423 | I &image_ctx = this->m_image_ctx; | |
424 | CephContext *cct = image_ctx.cct; | |
425 | ||
426 | if (!this->template append_op_event< | |
427 | DisableFeaturesRequest<I>, | |
428 | &DisableFeaturesRequest<I>::handle_append_op_event>(this)) { | |
429 | send_remove_object_map(); | |
430 | } | |
431 | ||
432 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
433 | } | |
434 | ||
435 | template <typename I> | |
436 | Context *DisableFeaturesRequest<I>::handle_append_op_event(int *result) { | |
437 | I &image_ctx = this->m_image_ctx; | |
438 | CephContext *cct = image_ctx.cct; | |
439 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
440 | ||
441 | if (*result < 0) { | |
442 | lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result) | |
443 | << dendl; | |
444 | return handle_finish(*result); | |
445 | } | |
446 | ||
447 | send_remove_object_map(); | |
448 | return nullptr; | |
449 | } | |
450 | ||
451 | template <typename I> | |
452 | void DisableFeaturesRequest<I>::send_remove_object_map() { | |
453 | I &image_ctx = this->m_image_ctx; | |
454 | CephContext *cct = image_ctx.cct; | |
455 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
456 | ||
457 | if ((m_features & RBD_FEATURE_OBJECT_MAP) == 0) { | |
458 | send_set_features(); | |
459 | return; | |
460 | } | |
461 | ||
462 | Context *ctx = create_context_callback< | |
463 | DisableFeaturesRequest<I>, | |
464 | &DisableFeaturesRequest<I>::handle_remove_object_map>(this); | |
465 | ||
466 | object_map::RemoveRequest<I> *req = | |
467 | object_map::RemoveRequest<I>::create(&image_ctx, ctx); | |
468 | req->send(); | |
469 | } | |
470 | ||
471 | template <typename I> | |
472 | Context *DisableFeaturesRequest<I>::handle_remove_object_map(int *result) { | |
473 | I &image_ctx = this->m_image_ctx; | |
474 | CephContext *cct = image_ctx.cct; | |
475 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
476 | ||
477 | if (*result < 0) { | |
478 | lderr(cct) << "failed to remove object map: " << cpp_strerror(*result) << dendl; | |
479 | return handle_finish(*result); | |
480 | } | |
481 | ||
482 | send_set_features(); | |
483 | return nullptr; | |
484 | } | |
485 | ||
486 | template <typename I> | |
487 | void DisableFeaturesRequest<I>::send_set_features() { | |
488 | I &image_ctx = this->m_image_ctx; | |
489 | CephContext *cct = image_ctx.cct; | |
490 | ldout(cct, 20) << this << " " << __func__ << ": new_features=" | |
491 | << m_new_features << ", features_mask=" << m_features_mask | |
492 | << dendl; | |
493 | ||
494 | librados::ObjectWriteOperation op; | |
495 | librbd::cls_client::set_features(&op, m_new_features, m_features_mask); | |
496 | ||
497 | using klass = DisableFeaturesRequest<I>; | |
498 | librados::AioCompletion *comp = | |
499 | create_rados_callback<klass, &klass::handle_set_features>(this); | |
500 | int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, comp, &op); | |
501 | assert(r == 0); | |
502 | comp->release(); | |
503 | } | |
504 | ||
505 | template <typename I> | |
506 | Context *DisableFeaturesRequest<I>::handle_set_features(int *result) { | |
507 | I &image_ctx = this->m_image_ctx; | |
508 | CephContext *cct = image_ctx.cct; | |
509 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
510 | ||
511 | if (*result == -EINVAL && (m_features_mask & RBD_FEATURE_JOURNALING) != 0) { | |
512 | // NOTE: infernalis OSDs will not accept a mask with new features, so | |
513 | // re-attempt with a reduced mask. | |
514 | ldout(cct, 5) << this << " " << __func__ | |
515 | << ": re-attempt with a reduced mask" << dendl; | |
516 | m_features_mask &= ~RBD_FEATURE_JOURNALING; | |
517 | send_set_features(); | |
518 | } | |
519 | ||
520 | if (*result < 0) { | |
521 | lderr(cct) << "failed to update features: " << cpp_strerror(*result) | |
522 | << dendl; | |
523 | return handle_finish(*result); | |
524 | } | |
525 | ||
526 | send_update_flags(); | |
527 | return nullptr; | |
528 | } | |
529 | ||
530 | template <typename I> | |
531 | void DisableFeaturesRequest<I>::send_update_flags() { | |
532 | I &image_ctx = this->m_image_ctx; | |
533 | CephContext *cct = image_ctx.cct; | |
534 | ||
535 | if (m_disable_flags == 0) { | |
536 | send_notify_update(); | |
537 | return; | |
538 | } | |
539 | ||
540 | ldout(cct, 20) << this << " " << __func__ << ": disable_flags=" | |
541 | << m_disable_flags << dendl; | |
542 | ||
543 | Context *ctx = create_context_callback< | |
544 | DisableFeaturesRequest<I>, | |
545 | &DisableFeaturesRequest<I>::handle_update_flags>(this); | |
546 | ||
547 | image::SetFlagsRequest<I> *req = | |
548 | image::SetFlagsRequest<I>::create(&image_ctx, 0, m_disable_flags, ctx); | |
549 | req->send(); | |
550 | } | |
551 | ||
552 | template <typename I> | |
553 | Context *DisableFeaturesRequest<I>::handle_update_flags(int *result) { | |
554 | I &image_ctx = this->m_image_ctx; | |
555 | CephContext *cct = image_ctx.cct; | |
556 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
557 | ||
558 | if (*result < 0) { | |
559 | lderr(cct) << "failed to update image flags: " << cpp_strerror(*result) | |
560 | << dendl; | |
561 | return handle_finish(*result); | |
562 | } | |
563 | ||
564 | send_notify_update(); | |
565 | return nullptr; | |
566 | } | |
567 | ||
568 | template <typename I> | |
569 | void DisableFeaturesRequest<I>::send_notify_update() { | |
570 | I &image_ctx = this->m_image_ctx; | |
571 | CephContext *cct = image_ctx.cct; | |
572 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
573 | ||
574 | Context *ctx = create_context_callback< | |
575 | DisableFeaturesRequest<I>, | |
576 | &DisableFeaturesRequest<I>::handle_notify_update>(this); | |
577 | ||
578 | image_ctx.notify_update(ctx); | |
579 | } | |
580 | ||
581 | template <typename I> | |
582 | Context *DisableFeaturesRequest<I>::handle_notify_update(int *result) { | |
583 | I &image_ctx = this->m_image_ctx; | |
584 | CephContext *cct = image_ctx.cct; | |
585 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
586 | ||
587 | if (image_ctx.exclusive_lock == nullptr || !m_acquired_lock) { | |
588 | return handle_finish(*result); | |
589 | } | |
590 | ||
591 | send_release_exclusive_lock(); | |
592 | return nullptr; | |
593 | } | |
594 | ||
595 | template <typename I> | |
596 | void DisableFeaturesRequest<I>::send_release_exclusive_lock() { | |
597 | I &image_ctx = this->m_image_ctx; | |
598 | CephContext *cct = image_ctx.cct; | |
599 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
600 | ||
601 | Context *ctx = create_context_callback< | |
602 | DisableFeaturesRequest<I>, | |
603 | &DisableFeaturesRequest<I>::handle_release_exclusive_lock>(this); | |
604 | ||
605 | image_ctx.exclusive_lock->release_lock(ctx); | |
606 | } | |
607 | ||
608 | template <typename I> | |
609 | Context *DisableFeaturesRequest<I>::handle_release_exclusive_lock(int *result) { | |
610 | I &image_ctx = this->m_image_ctx; | |
611 | CephContext *cct = image_ctx.cct; | |
612 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
613 | ||
614 | return handle_finish(*result); | |
615 | } | |
616 | ||
617 | template <typename I> | |
618 | Context *DisableFeaturesRequest<I>::handle_finish(int r) { | |
619 | I &image_ctx = this->m_image_ctx; | |
620 | CephContext *cct = image_ctx.cct; | |
621 | ldout(cct, 20) << this << " " << __func__ << ": r=" << r << dendl; | |
622 | ||
623 | { | |
624 | RWLock::WLocker locker(image_ctx.owner_lock); | |
625 | if (image_ctx.exclusive_lock != nullptr && m_requests_blocked) { | |
626 | image_ctx.exclusive_lock->unblock_requests(); | |
627 | } | |
628 | ||
629 | image_ctx.io_work_queue->unblock_writes(); | |
630 | } | |
631 | image_ctx.state->handle_prepare_lock_complete(); | |
632 | ||
633 | return this->create_context_finisher(r); | |
634 | } | |
635 | ||
636 | } // namespace operation | |
637 | } // namespace librbd | |
638 | ||
639 | template class librbd::operation::DisableFeaturesRequest<librbd::ImageCtx>; |