]>
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 | ||
91327a77 | 163 | image_ctx.owner_lock.get_read(); |
7c673cae FG |
164 | if (*result < 0) { |
165 | lderr(cct) << "failed to lock image: " << cpp_strerror(*result) << dendl; | |
91327a77 | 166 | image_ctx.owner_lock.put_read(); |
7c673cae | 167 | return handle_finish(*result); |
91327a77 AA |
168 | } else if (image_ctx.exclusive_lock != nullptr && |
169 | !image_ctx.exclusive_lock->is_lock_owner()) { | |
7c673cae | 170 | lderr(cct) << "failed to acquire exclusive lock" << dendl; |
91327a77 AA |
171 | *result = image_ctx.exclusive_lock->get_unlocked_op_error(); |
172 | image_ctx.owner_lock.put_read(); | |
7c673cae FG |
173 | return handle_finish(*result); |
174 | } | |
175 | ||
176 | do { | |
7c673cae FG |
177 | m_features &= image_ctx.features; |
178 | m_new_features = image_ctx.features & ~m_features; | |
179 | m_features_mask = m_features; | |
180 | ||
181 | if ((m_features & RBD_FEATURE_EXCLUSIVE_LOCK) != 0) { | |
182 | if ((m_new_features & RBD_FEATURE_OBJECT_MAP) != 0 || | |
183 | (m_new_features & RBD_FEATURE_JOURNALING) != 0) { | |
184 | lderr(cct) << "cannot disable exclusive-lock. object-map " | |
185 | "or journaling must be disabled before " | |
186 | "disabling exclusive-lock." << dendl; | |
187 | *result = -EINVAL; | |
188 | break; | |
189 | } | |
190 | m_features_mask |= (RBD_FEATURE_OBJECT_MAP | | |
191 | RBD_FEATURE_JOURNALING); | |
192 | } | |
193 | if ((m_features & RBD_FEATURE_FAST_DIFF) != 0) { | |
194 | m_disable_flags |= RBD_FLAG_FAST_DIFF_INVALID; | |
195 | } | |
196 | if ((m_features & RBD_FEATURE_OBJECT_MAP) != 0) { | |
197 | if ((m_new_features & RBD_FEATURE_FAST_DIFF) != 0) { | |
198 | lderr(cct) << "cannot disable object-map. fast-diff must be " | |
199 | "disabled before disabling object-map." << dendl; | |
200 | *result = -EINVAL; | |
201 | break; | |
202 | } | |
203 | m_disable_flags |= RBD_FLAG_OBJECT_MAP_INVALID; | |
204 | } | |
205 | } while (false); | |
91327a77 | 206 | image_ctx.owner_lock.put_read(); |
7c673cae FG |
207 | |
208 | if (*result < 0) { | |
209 | return handle_finish(*result); | |
210 | } | |
211 | ||
212 | send_get_mirror_mode(); | |
213 | return nullptr; | |
214 | } | |
215 | ||
216 | template <typename I> | |
217 | void DisableFeaturesRequest<I>::send_get_mirror_mode() { | |
218 | I &image_ctx = this->m_image_ctx; | |
219 | CephContext *cct = image_ctx.cct; | |
220 | ||
221 | if ((m_features & RBD_FEATURE_JOURNALING) == 0) { | |
222 | send_append_op_event(); | |
223 | return; | |
224 | } | |
225 | ||
226 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
227 | ||
228 | librados::ObjectReadOperation op; | |
229 | cls_client::mirror_mode_get_start(&op); | |
230 | ||
231 | using klass = DisableFeaturesRequest<I>; | |
232 | librados::AioCompletion *comp = | |
233 | create_rados_callback<klass, &klass::handle_get_mirror_mode>(this); | |
234 | m_out_bl.clear(); | |
235 | int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl); | |
236 | assert(r == 0); | |
237 | comp->release(); | |
238 | } | |
239 | ||
240 | template <typename I> | |
241 | Context *DisableFeaturesRequest<I>::handle_get_mirror_mode(int *result) { | |
242 | I &image_ctx = this->m_image_ctx; | |
243 | CephContext *cct = image_ctx.cct; | |
244 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
245 | ||
246 | if (*result == 0) { | |
247 | bufferlist::iterator it = m_out_bl.begin(); | |
248 | *result = cls_client::mirror_mode_get_finish(&it, &m_mirror_mode); | |
249 | } | |
250 | ||
251 | if (*result < 0 && *result != -ENOENT) { | |
252 | lderr(cct) << "failed to retrieve pool mirror mode: " | |
253 | << cpp_strerror(*result) << dendl; | |
254 | return handle_finish(*result); | |
255 | } | |
256 | ||
257 | ldout(cct, 20) << this << " " << __func__ << ": m_mirror_mode=" | |
258 | << m_mirror_mode << dendl; | |
259 | ||
260 | send_get_mirror_image(); | |
261 | return nullptr; | |
262 | } | |
263 | ||
264 | template <typename I> | |
265 | void DisableFeaturesRequest<I>::send_get_mirror_image() { | |
266 | I &image_ctx = this->m_image_ctx; | |
267 | CephContext *cct = image_ctx.cct; | |
268 | ||
269 | if (m_mirror_mode != cls::rbd::MIRROR_MODE_IMAGE) { | |
270 | send_disable_mirror_image(); | |
271 | return; | |
272 | } | |
273 | ||
274 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
275 | ||
276 | librados::ObjectReadOperation op; | |
277 | cls_client::mirror_image_get_start(&op, image_ctx.id); | |
278 | ||
279 | using klass = DisableFeaturesRequest<I>; | |
280 | librados::AioCompletion *comp = | |
281 | create_rados_callback<klass, &klass::handle_get_mirror_image>(this); | |
282 | m_out_bl.clear(); | |
283 | int r = image_ctx.md_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl); | |
284 | assert(r == 0); | |
285 | comp->release(); | |
286 | } | |
287 | ||
288 | template <typename I> | |
289 | Context *DisableFeaturesRequest<I>::handle_get_mirror_image(int *result) { | |
290 | I &image_ctx = this->m_image_ctx; | |
291 | CephContext *cct = image_ctx.cct; | |
292 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
293 | ||
294 | cls::rbd::MirrorImage mirror_image; | |
295 | ||
296 | if (*result == 0) { | |
297 | bufferlist::iterator it = m_out_bl.begin(); | |
298 | *result = cls_client::mirror_image_get_finish(&it, &mirror_image); | |
299 | } | |
300 | ||
301 | if (*result < 0 && *result != -ENOENT) { | |
302 | lderr(cct) << "failed to retrieve pool mirror image: " | |
303 | << cpp_strerror(*result) << dendl; | |
304 | return handle_finish(*result); | |
305 | } | |
306 | ||
307 | if ((mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) && !m_force) { | |
308 | lderr(cct) << "cannot disable journaling: image mirroring " | |
309 | << "enabled and mirror pool mode set to image" | |
310 | << dendl; | |
311 | *result = -EINVAL; | |
312 | return handle_finish(*result); | |
313 | } | |
314 | ||
315 | send_disable_mirror_image(); | |
316 | return nullptr; | |
317 | } | |
318 | ||
319 | template <typename I> | |
320 | void DisableFeaturesRequest<I>::send_disable_mirror_image() { | |
321 | I &image_ctx = this->m_image_ctx; | |
322 | CephContext *cct = image_ctx.cct; | |
323 | ||
324 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
325 | ||
326 | Context *ctx = create_context_callback< | |
327 | DisableFeaturesRequest<I>, | |
328 | &DisableFeaturesRequest<I>::handle_disable_mirror_image>(this); | |
329 | ||
330 | mirror::DisableRequest<I> *req = | |
331 | mirror::DisableRequest<I>::create(&image_ctx, m_force, true, ctx); | |
332 | req->send(); | |
333 | } | |
334 | ||
335 | template <typename I> | |
336 | Context *DisableFeaturesRequest<I>::handle_disable_mirror_image(int *result) { | |
337 | I &image_ctx = this->m_image_ctx; | |
338 | CephContext *cct = image_ctx.cct; | |
339 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
340 | ||
341 | if (*result < 0) { | |
342 | lderr(cct) << "failed to disable image mirroring: " << cpp_strerror(*result) | |
343 | << dendl; | |
344 | // not fatal | |
345 | } | |
346 | ||
347 | send_close_journal(); | |
348 | return nullptr; | |
349 | } | |
350 | ||
351 | template <typename I> | |
352 | void DisableFeaturesRequest<I>::send_close_journal() { | |
353 | I &image_ctx = this->m_image_ctx; | |
354 | CephContext *cct = image_ctx.cct; | |
355 | ||
356 | { | |
357 | RWLock::WLocker locker(image_ctx.owner_lock); | |
358 | if (image_ctx.journal != nullptr) { | |
7c673cae FG |
359 | ldout(cct, 20) << this << " " << __func__ << dendl; |
360 | ||
224ce89b | 361 | std::swap(m_journal, image_ctx.journal); |
7c673cae FG |
362 | Context *ctx = create_context_callback< |
363 | DisableFeaturesRequest<I>, | |
364 | &DisableFeaturesRequest<I>::handle_close_journal>(this); | |
365 | ||
224ce89b | 366 | m_journal->close(ctx); |
7c673cae FG |
367 | return; |
368 | } | |
369 | } | |
370 | ||
371 | send_remove_journal(); | |
372 | } | |
373 | ||
374 | template <typename I> | |
375 | Context *DisableFeaturesRequest<I>::handle_close_journal(int *result) { | |
376 | I &image_ctx = this->m_image_ctx; | |
377 | CephContext *cct = image_ctx.cct; | |
378 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
379 | ||
380 | if (*result < 0) { | |
381 | lderr(cct) << "failed to close image journal: " << cpp_strerror(*result) | |
382 | << dendl; | |
7c673cae FG |
383 | } |
384 | ||
224ce89b WB |
385 | assert(m_journal != nullptr); |
386 | delete m_journal; | |
387 | m_journal = nullptr; | |
388 | ||
7c673cae FG |
389 | send_remove_journal(); |
390 | return nullptr; | |
391 | } | |
392 | ||
393 | template <typename I> | |
394 | void DisableFeaturesRequest<I>::send_remove_journal() { | |
395 | I &image_ctx = this->m_image_ctx; | |
396 | CephContext *cct = image_ctx.cct; | |
397 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
398 | ||
399 | Context *ctx = create_context_callback< | |
400 | DisableFeaturesRequest<I>, | |
401 | &DisableFeaturesRequest<I>::handle_remove_journal>(this); | |
402 | ||
403 | journal::RemoveRequest<I> *req = journal::RemoveRequest<I>::create( | |
404 | image_ctx.md_ctx, image_ctx.id, librbd::Journal<>::IMAGE_CLIENT_ID, | |
405 | image_ctx.op_work_queue, ctx); | |
406 | ||
407 | req->send(); | |
408 | } | |
409 | ||
410 | template <typename I> | |
411 | Context *DisableFeaturesRequest<I>::handle_remove_journal(int *result) { | |
412 | I &image_ctx = this->m_image_ctx; | |
413 | CephContext *cct = image_ctx.cct; | |
414 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
415 | ||
416 | if (*result < 0) { | |
417 | lderr(cct) << "failed to remove image journal: " << cpp_strerror(*result) | |
418 | << dendl; | |
419 | return handle_finish(*result); | |
420 | } | |
421 | ||
422 | send_append_op_event(); | |
423 | return nullptr; | |
424 | } | |
425 | ||
426 | template <typename I> | |
427 | void DisableFeaturesRequest<I>::send_append_op_event() { | |
428 | I &image_ctx = this->m_image_ctx; | |
429 | CephContext *cct = image_ctx.cct; | |
430 | ||
431 | if (!this->template append_op_event< | |
432 | DisableFeaturesRequest<I>, | |
433 | &DisableFeaturesRequest<I>::handle_append_op_event>(this)) { | |
434 | send_remove_object_map(); | |
435 | } | |
436 | ||
437 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
438 | } | |
439 | ||
440 | template <typename I> | |
441 | Context *DisableFeaturesRequest<I>::handle_append_op_event(int *result) { | |
442 | I &image_ctx = this->m_image_ctx; | |
443 | CephContext *cct = image_ctx.cct; | |
444 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
445 | ||
446 | if (*result < 0) { | |
447 | lderr(cct) << "failed to commit journal entry: " << cpp_strerror(*result) | |
448 | << dendl; | |
449 | return handle_finish(*result); | |
450 | } | |
451 | ||
452 | send_remove_object_map(); | |
453 | return nullptr; | |
454 | } | |
455 | ||
456 | template <typename I> | |
457 | void DisableFeaturesRequest<I>::send_remove_object_map() { | |
458 | I &image_ctx = this->m_image_ctx; | |
459 | CephContext *cct = image_ctx.cct; | |
460 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
461 | ||
462 | if ((m_features & RBD_FEATURE_OBJECT_MAP) == 0) { | |
463 | send_set_features(); | |
464 | return; | |
465 | } | |
466 | ||
467 | Context *ctx = create_context_callback< | |
468 | DisableFeaturesRequest<I>, | |
469 | &DisableFeaturesRequest<I>::handle_remove_object_map>(this); | |
470 | ||
471 | object_map::RemoveRequest<I> *req = | |
472 | object_map::RemoveRequest<I>::create(&image_ctx, ctx); | |
473 | req->send(); | |
474 | } | |
475 | ||
476 | template <typename I> | |
477 | Context *DisableFeaturesRequest<I>::handle_remove_object_map(int *result) { | |
478 | I &image_ctx = this->m_image_ctx; | |
479 | CephContext *cct = image_ctx.cct; | |
480 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
481 | ||
482 | if (*result < 0) { | |
483 | lderr(cct) << "failed to remove object map: " << cpp_strerror(*result) << dendl; | |
484 | return handle_finish(*result); | |
485 | } | |
486 | ||
487 | send_set_features(); | |
488 | return nullptr; | |
489 | } | |
490 | ||
491 | template <typename I> | |
492 | void DisableFeaturesRequest<I>::send_set_features() { | |
493 | I &image_ctx = this->m_image_ctx; | |
494 | CephContext *cct = image_ctx.cct; | |
495 | ldout(cct, 20) << this << " " << __func__ << ": new_features=" | |
496 | << m_new_features << ", features_mask=" << m_features_mask | |
497 | << dendl; | |
498 | ||
499 | librados::ObjectWriteOperation op; | |
500 | librbd::cls_client::set_features(&op, m_new_features, m_features_mask); | |
501 | ||
502 | using klass = DisableFeaturesRequest<I>; | |
503 | librados::AioCompletion *comp = | |
504 | create_rados_callback<klass, &klass::handle_set_features>(this); | |
505 | int r = image_ctx.md_ctx.aio_operate(image_ctx.header_oid, comp, &op); | |
506 | assert(r == 0); | |
507 | comp->release(); | |
508 | } | |
509 | ||
510 | template <typename I> | |
511 | Context *DisableFeaturesRequest<I>::handle_set_features(int *result) { | |
512 | I &image_ctx = this->m_image_ctx; | |
513 | CephContext *cct = image_ctx.cct; | |
514 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
515 | ||
516 | if (*result == -EINVAL && (m_features_mask & RBD_FEATURE_JOURNALING) != 0) { | |
517 | // NOTE: infernalis OSDs will not accept a mask with new features, so | |
518 | // re-attempt with a reduced mask. | |
519 | ldout(cct, 5) << this << " " << __func__ | |
520 | << ": re-attempt with a reduced mask" << dendl; | |
521 | m_features_mask &= ~RBD_FEATURE_JOURNALING; | |
522 | send_set_features(); | |
523 | } | |
524 | ||
525 | if (*result < 0) { | |
526 | lderr(cct) << "failed to update features: " << cpp_strerror(*result) | |
527 | << dendl; | |
528 | return handle_finish(*result); | |
529 | } | |
530 | ||
531 | send_update_flags(); | |
532 | return nullptr; | |
533 | } | |
534 | ||
535 | template <typename I> | |
536 | void DisableFeaturesRequest<I>::send_update_flags() { | |
537 | I &image_ctx = this->m_image_ctx; | |
538 | CephContext *cct = image_ctx.cct; | |
539 | ||
540 | if (m_disable_flags == 0) { | |
541 | send_notify_update(); | |
542 | return; | |
543 | } | |
544 | ||
545 | ldout(cct, 20) << this << " " << __func__ << ": disable_flags=" | |
546 | << m_disable_flags << dendl; | |
547 | ||
548 | Context *ctx = create_context_callback< | |
549 | DisableFeaturesRequest<I>, | |
550 | &DisableFeaturesRequest<I>::handle_update_flags>(this); | |
551 | ||
552 | image::SetFlagsRequest<I> *req = | |
553 | image::SetFlagsRequest<I>::create(&image_ctx, 0, m_disable_flags, ctx); | |
554 | req->send(); | |
555 | } | |
556 | ||
557 | template <typename I> | |
558 | Context *DisableFeaturesRequest<I>::handle_update_flags(int *result) { | |
559 | I &image_ctx = this->m_image_ctx; | |
560 | CephContext *cct = image_ctx.cct; | |
561 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
562 | ||
563 | if (*result < 0) { | |
564 | lderr(cct) << "failed to update image flags: " << cpp_strerror(*result) | |
565 | << dendl; | |
566 | return handle_finish(*result); | |
567 | } | |
568 | ||
569 | send_notify_update(); | |
570 | return nullptr; | |
571 | } | |
572 | ||
573 | template <typename I> | |
574 | void DisableFeaturesRequest<I>::send_notify_update() { | |
575 | I &image_ctx = this->m_image_ctx; | |
576 | CephContext *cct = image_ctx.cct; | |
577 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
578 | ||
579 | Context *ctx = create_context_callback< | |
580 | DisableFeaturesRequest<I>, | |
581 | &DisableFeaturesRequest<I>::handle_notify_update>(this); | |
582 | ||
583 | image_ctx.notify_update(ctx); | |
584 | } | |
585 | ||
586 | template <typename I> | |
587 | Context *DisableFeaturesRequest<I>::handle_notify_update(int *result) { | |
588 | I &image_ctx = this->m_image_ctx; | |
589 | CephContext *cct = image_ctx.cct; | |
590 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
591 | ||
592 | if (image_ctx.exclusive_lock == nullptr || !m_acquired_lock) { | |
593 | return handle_finish(*result); | |
594 | } | |
595 | ||
596 | send_release_exclusive_lock(); | |
597 | return nullptr; | |
598 | } | |
599 | ||
600 | template <typename I> | |
601 | void DisableFeaturesRequest<I>::send_release_exclusive_lock() { | |
602 | I &image_ctx = this->m_image_ctx; | |
603 | CephContext *cct = image_ctx.cct; | |
604 | ldout(cct, 20) << this << " " << __func__ << dendl; | |
605 | ||
606 | Context *ctx = create_context_callback< | |
607 | DisableFeaturesRequest<I>, | |
608 | &DisableFeaturesRequest<I>::handle_release_exclusive_lock>(this); | |
609 | ||
610 | image_ctx.exclusive_lock->release_lock(ctx); | |
611 | } | |
612 | ||
613 | template <typename I> | |
614 | Context *DisableFeaturesRequest<I>::handle_release_exclusive_lock(int *result) { | |
615 | I &image_ctx = this->m_image_ctx; | |
616 | CephContext *cct = image_ctx.cct; | |
617 | ldout(cct, 20) << this << " " << __func__ << ": r=" << *result << dendl; | |
618 | ||
619 | return handle_finish(*result); | |
620 | } | |
621 | ||
622 | template <typename I> | |
623 | Context *DisableFeaturesRequest<I>::handle_finish(int r) { | |
624 | I &image_ctx = this->m_image_ctx; | |
625 | CephContext *cct = image_ctx.cct; | |
626 | ldout(cct, 20) << this << " " << __func__ << ": r=" << r << dendl; | |
627 | ||
628 | { | |
629 | RWLock::WLocker locker(image_ctx.owner_lock); | |
630 | if (image_ctx.exclusive_lock != nullptr && m_requests_blocked) { | |
631 | image_ctx.exclusive_lock->unblock_requests(); | |
632 | } | |
633 | ||
634 | image_ctx.io_work_queue->unblock_writes(); | |
635 | } | |
636 | image_ctx.state->handle_prepare_lock_complete(); | |
637 | ||
638 | return this->create_context_finisher(r); | |
639 | } | |
640 | ||
641 | } // namespace operation | |
642 | } // namespace librbd | |
643 | ||
644 | template class librbd::operation::DisableFeaturesRequest<librbd::ImageCtx>; |