]>
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/ImageState.h" | |
5 | #include "include/rbd/librbd.hpp" | |
6 | #include "common/dout.h" | |
7 | #include "common/errno.h" | |
8 | #include "common/Cond.h" | |
9 | #include "common/WorkQueue.h" | |
f67539c2 | 10 | #include "librbd/AsioEngine.h" |
7c673cae | 11 | #include "librbd/ImageCtx.h" |
f67539c2 | 12 | #include "librbd/TaskFinisher.h" |
7c673cae | 13 | #include "librbd/Utils.h" |
f67539c2 | 14 | #include "librbd/asio/ContextWQ.h" |
7c673cae FG |
15 | #include "librbd/image/CloseRequest.h" |
16 | #include "librbd/image/OpenRequest.h" | |
17 | #include "librbd/image/RefreshRequest.h" | |
18 | #include "librbd/image/SetSnapRequest.h" | |
19 | ||
20 | #define dout_subsys ceph_subsys_rbd | |
21 | #undef dout_prefix | |
22 | #define dout_prefix *_dout << "librbd::ImageState: " << this << " " | |
23 | ||
24 | namespace librbd { | |
25 | ||
26 | using util::create_async_context_callback; | |
27 | using util::create_context_callback; | |
28 | ||
29 | class ImageUpdateWatchers { | |
30 | public: | |
31 | ||
11fdf7f2 | 32 | explicit ImageUpdateWatchers(CephContext *cct) : m_cct(cct), |
9f95a23c | 33 | m_lock(ceph::make_mutex(util::unique_lock_name("librbd::ImageUpdateWatchers::m_lock", this))) { |
7c673cae FG |
34 | } |
35 | ||
36 | ~ImageUpdateWatchers() { | |
11fdf7f2 TL |
37 | ceph_assert(m_watchers.empty()); |
38 | ceph_assert(m_in_flight.empty()); | |
39 | ceph_assert(m_pending_unregister.empty()); | |
40 | ceph_assert(m_on_shut_down_finish == nullptr); | |
7c673cae FG |
41 | |
42 | destroy_work_queue(); | |
43 | } | |
44 | ||
45 | void flush(Context *on_finish) { | |
46 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << dendl; | |
47 | { | |
9f95a23c | 48 | std::lock_guard locker{m_lock}; |
7c673cae | 49 | if (!m_in_flight.empty()) { |
9f95a23c | 50 | Context *ctx = new LambdaContext( |
7c673cae FG |
51 | [this, on_finish](int r) { |
52 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ | |
53 | << ": completing flush" << dendl; | |
54 | on_finish->complete(r); | |
55 | }); | |
56 | m_work_queue->queue(ctx, 0); | |
57 | return; | |
58 | } | |
59 | } | |
60 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ | |
61 | << ": completing flush" << dendl; | |
62 | on_finish->complete(0); | |
63 | } | |
64 | ||
65 | void shut_down(Context *on_finish) { | |
66 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << dendl; | |
67 | { | |
9f95a23c | 68 | std::lock_guard locker{m_lock}; |
11fdf7f2 | 69 | ceph_assert(m_on_shut_down_finish == nullptr); |
7c673cae FG |
70 | m_watchers.clear(); |
71 | if (!m_in_flight.empty()) { | |
72 | m_on_shut_down_finish = on_finish; | |
73 | return; | |
74 | } | |
75 | } | |
76 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ | |
77 | << ": completing shut down" << dendl; | |
78 | on_finish->complete(0); | |
79 | } | |
80 | ||
81 | void register_watcher(UpdateWatchCtx *watcher, uint64_t *handle) { | |
f67539c2 TL |
82 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << ": watcher=" |
83 | << watcher << dendl; | |
7c673cae | 84 | |
9f95a23c | 85 | std::lock_guard locker{m_lock}; |
11fdf7f2 | 86 | ceph_assert(m_on_shut_down_finish == nullptr); |
7c673cae FG |
87 | |
88 | create_work_queue(); | |
89 | ||
90 | *handle = m_next_handle++; | |
91 | m_watchers.insert(std::make_pair(*handle, watcher)); | |
92 | } | |
93 | ||
94 | void unregister_watcher(uint64_t handle, Context *on_finish) { | |
95 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << ": handle=" | |
96 | << handle << dendl; | |
97 | int r = 0; | |
98 | { | |
9f95a23c | 99 | std::lock_guard locker{m_lock}; |
7c673cae FG |
100 | auto it = m_watchers.find(handle); |
101 | if (it == m_watchers.end()) { | |
102 | r = -ENOENT; | |
103 | } else { | |
104 | if (m_in_flight.find(handle) != m_in_flight.end()) { | |
11fdf7f2 | 105 | ceph_assert(m_pending_unregister.find(handle) == m_pending_unregister.end()); |
7c673cae FG |
106 | m_pending_unregister[handle] = on_finish; |
107 | on_finish = nullptr; | |
108 | } | |
109 | m_watchers.erase(it); | |
110 | } | |
111 | } | |
112 | ||
113 | if (on_finish) { | |
114 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ | |
115 | << ": completing unregister" << dendl; | |
116 | on_finish->complete(r); | |
117 | } | |
118 | } | |
119 | ||
120 | void notify() { | |
121 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << dendl; | |
122 | ||
9f95a23c | 123 | std::lock_guard locker{m_lock}; |
7c673cae FG |
124 | for (auto it : m_watchers) { |
125 | send_notify(it.first, it.second); | |
126 | } | |
127 | } | |
128 | ||
129 | void send_notify(uint64_t handle, UpdateWatchCtx *watcher) { | |
9f95a23c | 130 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
131 | |
132 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << ": handle=" | |
133 | << handle << ", watcher=" << watcher << dendl; | |
134 | ||
135 | m_in_flight.insert(handle); | |
136 | ||
9f95a23c | 137 | Context *ctx = new LambdaContext( |
7c673cae FG |
138 | [this, handle, watcher](int r) { |
139 | handle_notify(handle, watcher); | |
140 | }); | |
141 | ||
142 | m_work_queue->queue(ctx, 0); | |
143 | } | |
144 | ||
145 | void handle_notify(uint64_t handle, UpdateWatchCtx *watcher) { | |
146 | ||
147 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ << ": handle=" | |
148 | << handle << ", watcher=" << watcher << dendl; | |
149 | ||
150 | watcher->handle_notify(); | |
151 | ||
152 | Context *on_unregister_finish = nullptr; | |
153 | Context *on_shut_down_finish = nullptr; | |
154 | ||
155 | { | |
9f95a23c | 156 | std::lock_guard locker{m_lock}; |
7c673cae FG |
157 | |
158 | auto in_flight_it = m_in_flight.find(handle); | |
11fdf7f2 | 159 | ceph_assert(in_flight_it != m_in_flight.end()); |
7c673cae FG |
160 | m_in_flight.erase(in_flight_it); |
161 | ||
162 | // If there is no more in flight notifications for this watcher | |
163 | // and it is pending unregister, complete it now. | |
164 | if (m_in_flight.find(handle) == m_in_flight.end()) { | |
165 | auto it = m_pending_unregister.find(handle); | |
166 | if (it != m_pending_unregister.end()) { | |
167 | on_unregister_finish = it->second; | |
168 | m_pending_unregister.erase(it); | |
169 | } | |
170 | } | |
171 | ||
172 | if (m_in_flight.empty()) { | |
11fdf7f2 | 173 | ceph_assert(m_pending_unregister.empty()); |
7c673cae FG |
174 | if (m_on_shut_down_finish != nullptr) { |
175 | std::swap(m_on_shut_down_finish, on_shut_down_finish); | |
176 | } | |
177 | } | |
178 | } | |
179 | ||
180 | if (on_unregister_finish != nullptr) { | |
181 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ | |
182 | << ": completing unregister" << dendl; | |
183 | on_unregister_finish->complete(0); | |
184 | } | |
185 | ||
186 | if (on_shut_down_finish != nullptr) { | |
187 | ldout(m_cct, 20) << "ImageUpdateWatchers::" << __func__ | |
188 | << ": completing shut down" << dendl; | |
189 | on_shut_down_finish->complete(0); | |
190 | } | |
191 | } | |
192 | ||
193 | private: | |
194 | class ThreadPoolSingleton : public ThreadPool { | |
195 | public: | |
196 | explicit ThreadPoolSingleton(CephContext *cct) | |
197 | : ThreadPool(cct, "librbd::ImageUpdateWatchers::thread_pool", "tp_librbd", | |
198 | 1) { | |
199 | start(); | |
200 | } | |
201 | ~ThreadPoolSingleton() override { | |
202 | stop(); | |
203 | } | |
204 | }; | |
205 | ||
206 | CephContext *m_cct; | |
9f95a23c | 207 | ceph::mutex m_lock; |
7c673cae FG |
208 | ContextWQ *m_work_queue = nullptr; |
209 | std::map<uint64_t, UpdateWatchCtx*> m_watchers; | |
210 | uint64_t m_next_handle = 0; | |
211 | std::multiset<uint64_t> m_in_flight; | |
212 | std::map<uint64_t, Context*> m_pending_unregister; | |
213 | Context *m_on_shut_down_finish = nullptr; | |
214 | ||
215 | void create_work_queue() { | |
216 | if (m_work_queue != nullptr) { | |
217 | return; | |
218 | } | |
11fdf7f2 TL |
219 | auto& thread_pool = m_cct->lookup_or_create_singleton_object< |
220 | ThreadPoolSingleton>("librbd::ImageUpdateWatchers::thread_pool", | |
221 | false, m_cct); | |
f67539c2 TL |
222 | m_work_queue = new ContextWQ("librbd::ImageUpdateWatchers::work_queue", |
223 | ceph::make_timespan( | |
224 | m_cct->_conf.get_val<uint64_t>("rbd_op_thread_timeout")), | |
225 | &thread_pool); | |
7c673cae FG |
226 | } |
227 | ||
228 | void destroy_work_queue() { | |
229 | if (m_work_queue == nullptr) { | |
230 | return; | |
231 | } | |
232 | m_work_queue->drain(); | |
233 | delete m_work_queue; | |
234 | } | |
235 | }; | |
236 | ||
f67539c2 TL |
237 | class QuiesceWatchers { |
238 | public: | |
239 | explicit QuiesceWatchers(CephContext *cct, asio::ContextWQ* work_queue) | |
240 | : m_cct(cct), | |
241 | m_work_queue(work_queue), | |
242 | m_lock(ceph::make_mutex(util::unique_lock_name( | |
243 | "librbd::QuiesceWatchers::m_lock", this))) { | |
244 | } | |
245 | ||
246 | ~QuiesceWatchers() { | |
247 | ceph_assert(m_pending_unregister.empty()); | |
248 | ceph_assert(m_on_notify == nullptr); | |
249 | } | |
250 | ||
251 | void register_watcher(QuiesceWatchCtx *watcher, uint64_t *handle) { | |
252 | ldout(m_cct, 20) << "QuiesceWatchers::" << __func__ << ": watcher=" | |
253 | << watcher << dendl; | |
254 | ||
255 | std::lock_guard locker{m_lock}; | |
256 | ||
257 | *handle = m_next_handle++; | |
258 | m_watchers[*handle] = watcher; | |
259 | } | |
260 | ||
261 | void unregister_watcher(uint64_t handle, Context *on_finish) { | |
262 | int r = 0; | |
263 | { | |
264 | std::lock_guard locker{m_lock}; | |
265 | auto it = m_watchers.find(handle); | |
266 | if (it == m_watchers.end()) { | |
267 | r = -ENOENT; | |
268 | } else { | |
269 | if (m_on_notify != nullptr) { | |
270 | ceph_assert(!m_pending_unregister.count(handle)); | |
271 | m_pending_unregister[handle] = on_finish; | |
272 | on_finish = nullptr; | |
273 | } | |
274 | m_watchers.erase(it); | |
275 | } | |
276 | } | |
277 | ||
278 | if (on_finish) { | |
279 | ldout(m_cct, 20) << "QuiesceWatchers::" << __func__ | |
280 | << ": completing unregister " << handle << dendl; | |
281 | on_finish->complete(r); | |
282 | } | |
283 | } | |
284 | ||
285 | void notify_quiesce(Context *on_finish) { | |
286 | std::lock_guard locker{m_lock}; | |
287 | if (m_blocked) { | |
288 | ldout(m_cct, 20) << "QuiesceWatchers::" << __func__ << ": queue" << dendl; | |
289 | m_pending_notify.push_back(on_finish); | |
290 | return; | |
291 | } | |
292 | ||
293 | notify(QUIESCE, on_finish); | |
294 | } | |
295 | ||
296 | void notify_unquiesce(Context *on_finish) { | |
297 | std::lock_guard locker{m_lock}; | |
298 | ||
299 | notify(UNQUIESCE, on_finish); | |
300 | } | |
301 | ||
302 | void quiesce_complete(uint64_t handle, int r) { | |
303 | Context *on_notify = nullptr; | |
304 | { | |
305 | std::lock_guard locker{m_lock}; | |
306 | ceph_assert(m_on_notify != nullptr); | |
307 | ceph_assert(m_handle_quiesce_cnt > 0); | |
308 | ||
309 | m_handle_quiesce_cnt--; | |
310 | ||
311 | if (r < 0) { | |
312 | ldout(m_cct, 10) << "QuiesceWatchers::" << __func__ << ": watcher " | |
313 | << handle << " failed" << dendl; | |
314 | m_failed_watchers.insert(handle); | |
315 | m_ret_val = r; | |
316 | } | |
317 | ||
318 | if (m_handle_quiesce_cnt > 0) { | |
319 | return; | |
320 | } | |
321 | ||
322 | std::swap(on_notify, m_on_notify); | |
323 | r = m_ret_val; | |
324 | } | |
325 | ||
326 | on_notify->complete(r); | |
327 | } | |
328 | ||
329 | private: | |
330 | enum EventType {QUIESCE, UNQUIESCE}; | |
331 | ||
332 | CephContext *m_cct; | |
333 | asio::ContextWQ *m_work_queue; | |
334 | ||
335 | ceph::mutex m_lock; | |
336 | std::map<uint64_t, QuiesceWatchCtx*> m_watchers; | |
337 | uint64_t m_next_handle = 0; | |
338 | Context *m_on_notify = nullptr; | |
339 | std::list<Context *> m_pending_notify; | |
340 | std::map<uint64_t, Context*> m_pending_unregister; | |
341 | uint64_t m_handle_quiesce_cnt = 0; | |
342 | std::set<uint64_t> m_failed_watchers; | |
343 | bool m_blocked = false; | |
344 | int m_ret_val = 0; | |
345 | ||
346 | void notify(EventType event_type, Context *on_finish) { | |
347 | ceph_assert(ceph_mutex_is_locked(m_lock)); | |
348 | ||
349 | if (m_watchers.empty()) { | |
350 | m_work_queue->queue(on_finish); | |
351 | return; | |
352 | } | |
353 | ||
354 | ldout(m_cct, 20) << "QuiesceWatchers::" << __func__ << " event: " | |
355 | << event_type << dendl; | |
356 | ||
357 | Context *ctx = nullptr; | |
358 | if (event_type == QUIESCE) { | |
359 | ceph_assert(!m_blocked); | |
360 | ceph_assert(m_handle_quiesce_cnt == 0); | |
361 | ||
362 | m_blocked = true; | |
363 | m_handle_quiesce_cnt = m_watchers.size(); | |
364 | m_failed_watchers.clear(); | |
365 | m_ret_val = 0; | |
366 | } else { | |
367 | ceph_assert(event_type == UNQUIESCE); | |
368 | ceph_assert(m_blocked); | |
369 | ||
370 | ctx = create_async_context_callback( | |
371 | m_work_queue, create_context_callback< | |
372 | QuiesceWatchers, &QuiesceWatchers::handle_notify_unquiesce>(this)); | |
373 | } | |
374 | auto gather_ctx = new C_Gather(m_cct, ctx); | |
375 | ||
376 | ceph_assert(m_on_notify == nullptr); | |
377 | ||
378 | m_on_notify = on_finish; | |
379 | ||
380 | for (auto &[handle, watcher] : m_watchers) { | |
381 | send_notify(handle, watcher, event_type, gather_ctx->new_sub()); | |
382 | } | |
383 | ||
384 | gather_ctx->activate(); | |
385 | } | |
386 | ||
387 | void send_notify(uint64_t handle, QuiesceWatchCtx *watcher, | |
388 | EventType event_type, Context *on_finish) { | |
389 | auto ctx = new LambdaContext( | |
390 | [this, handle, watcher, event_type, on_finish](int) { | |
391 | ldout(m_cct, 20) << "QuiesceWatchers::" << __func__ << ": handle=" | |
392 | << handle << ", event_type=" << event_type << dendl; | |
393 | switch (event_type) { | |
394 | case QUIESCE: | |
395 | watcher->handle_quiesce(); | |
396 | break; | |
397 | case UNQUIESCE: | |
398 | { | |
399 | std::lock_guard locker{m_lock}; | |
400 | ||
401 | if (m_failed_watchers.count(handle)) { | |
402 | ldout(m_cct, 20) << "QuiesceWatchers::" << __func__ | |
403 | << ": skip for failed watcher" << dendl; | |
404 | break; | |
405 | } | |
406 | } | |
407 | watcher->handle_unquiesce(); | |
408 | break; | |
409 | default: | |
410 | ceph_abort_msgf("invalid event_type %d", event_type); | |
411 | } | |
412 | ||
413 | on_finish->complete(0); | |
414 | }); | |
415 | ||
416 | m_work_queue->queue(ctx); | |
417 | } | |
418 | ||
419 | void handle_notify_unquiesce(int r) { | |
420 | ldout(m_cct, 20) << "QuiesceWatchers::" << __func__ << ": r=" << r | |
421 | << dendl; | |
422 | ||
423 | ceph_assert(r == 0); | |
424 | ||
425 | std::unique_lock locker{m_lock}; | |
426 | ||
427 | if (!m_pending_unregister.empty()) { | |
428 | std::map<uint64_t, Context*> pending_unregister; | |
429 | std::swap(pending_unregister, m_pending_unregister); | |
430 | locker.unlock(); | |
431 | for (auto &it : pending_unregister) { | |
432 | ldout(m_cct, 20) << "QuiesceWatchers::" << __func__ | |
433 | << ": completing unregister " << it.first << dendl; | |
434 | it.second->complete(0); | |
435 | } | |
436 | locker.lock(); | |
437 | } | |
438 | ||
439 | Context *on_notify = nullptr; | |
440 | std::swap(on_notify, m_on_notify); | |
441 | ||
442 | ceph_assert(m_blocked); | |
443 | m_blocked = false; | |
444 | ||
445 | if (!m_pending_notify.empty()) { | |
446 | auto on_finish = m_pending_notify.front(); | |
447 | m_pending_notify.pop_front(); | |
448 | notify(QUIESCE, on_finish); | |
449 | } | |
450 | ||
451 | locker.unlock(); | |
452 | on_notify->complete(0); | |
453 | } | |
454 | }; | |
455 | ||
7c673cae FG |
456 | template <typename I> |
457 | ImageState<I>::ImageState(I *image_ctx) | |
458 | : m_image_ctx(image_ctx), m_state(STATE_UNINITIALIZED), | |
9f95a23c | 459 | m_lock(ceph::make_mutex(util::unique_lock_name("librbd::ImageState::m_lock", this))), |
7c673cae | 460 | m_last_refresh(0), m_refresh_seq(0), |
f67539c2 TL |
461 | m_update_watchers(new ImageUpdateWatchers(image_ctx->cct)), |
462 | m_quiesce_watchers(new QuiesceWatchers( | |
463 | image_ctx->cct, image_ctx->asio_engine->get_work_queue())) { | |
7c673cae FG |
464 | } |
465 | ||
466 | template <typename I> | |
467 | ImageState<I>::~ImageState() { | |
11fdf7f2 | 468 | ceph_assert(m_state == STATE_UNINITIALIZED || m_state == STATE_CLOSED); |
7c673cae | 469 | delete m_update_watchers; |
f67539c2 | 470 | delete m_quiesce_watchers; |
7c673cae FG |
471 | } |
472 | ||
473 | template <typename I> | |
11fdf7f2 | 474 | int ImageState<I>::open(uint64_t flags) { |
7c673cae | 475 | C_SaferCond ctx; |
11fdf7f2 | 476 | open(flags, &ctx); |
7c673cae FG |
477 | |
478 | int r = ctx.wait(); | |
7c673cae FG |
479 | return r; |
480 | } | |
481 | ||
482 | template <typename I> | |
11fdf7f2 | 483 | void ImageState<I>::open(uint64_t flags, Context *on_finish) { |
7c673cae FG |
484 | CephContext *cct = m_image_ctx->cct; |
485 | ldout(cct, 20) << __func__ << dendl; | |
486 | ||
9f95a23c | 487 | m_lock.lock(); |
11fdf7f2 TL |
488 | ceph_assert(m_state == STATE_UNINITIALIZED); |
489 | m_open_flags = flags; | |
7c673cae FG |
490 | |
491 | Action action(ACTION_TYPE_OPEN); | |
492 | action.refresh_seq = m_refresh_seq; | |
493 | ||
494 | execute_action_unlock(action, on_finish); | |
495 | } | |
496 | ||
497 | template <typename I> | |
498 | int ImageState<I>::close() { | |
499 | C_SaferCond ctx; | |
500 | close(&ctx); | |
501 | ||
502 | int r = ctx.wait(); | |
7c673cae FG |
503 | return r; |
504 | } | |
505 | ||
506 | template <typename I> | |
507 | void ImageState<I>::close(Context *on_finish) { | |
508 | CephContext *cct = m_image_ctx->cct; | |
509 | ldout(cct, 20) << __func__ << dendl; | |
510 | ||
9f95a23c | 511 | m_lock.lock(); |
11fdf7f2 | 512 | ceph_assert(!is_closed()); |
7c673cae FG |
513 | |
514 | Action action(ACTION_TYPE_CLOSE); | |
515 | action.refresh_seq = m_refresh_seq; | |
516 | execute_action_unlock(action, on_finish); | |
517 | } | |
518 | ||
519 | template <typename I> | |
520 | void ImageState<I>::handle_update_notification() { | |
9f95a23c | 521 | std::lock_guard locker{m_lock}; |
7c673cae FG |
522 | ++m_refresh_seq; |
523 | ||
524 | CephContext *cct = m_image_ctx->cct; | |
525 | ldout(cct, 20) << __func__ << ": refresh_seq = " << m_refresh_seq << ", " | |
526 | << "last_refresh = " << m_last_refresh << dendl; | |
527 | ||
9f95a23c TL |
528 | switch (m_state) { |
529 | case STATE_UNINITIALIZED: | |
530 | case STATE_CLOSED: | |
531 | case STATE_OPENING: | |
532 | case STATE_CLOSING: | |
533 | ldout(cct, 5) << "dropping update notification to watchers" << dendl; | |
534 | return; | |
535 | default: | |
536 | break; | |
7c673cae | 537 | } |
9f95a23c TL |
538 | |
539 | m_update_watchers->notify(); | |
7c673cae FG |
540 | } |
541 | ||
542 | template <typename I> | |
543 | bool ImageState<I>::is_refresh_required() const { | |
9f95a23c | 544 | std::lock_guard locker{m_lock}; |
7c673cae FG |
545 | return (m_last_refresh != m_refresh_seq || find_pending_refresh() != nullptr); |
546 | } | |
547 | ||
548 | template <typename I> | |
549 | int ImageState<I>::refresh() { | |
550 | C_SaferCond refresh_ctx; | |
551 | refresh(&refresh_ctx); | |
552 | return refresh_ctx.wait(); | |
553 | } | |
554 | ||
555 | template <typename I> | |
556 | void ImageState<I>::refresh(Context *on_finish) { | |
557 | CephContext *cct = m_image_ctx->cct; | |
558 | ldout(cct, 20) << __func__ << dendl; | |
559 | ||
9f95a23c | 560 | m_lock.lock(); |
7c673cae | 561 | if (is_closed()) { |
9f95a23c | 562 | m_lock.unlock(); |
7c673cae FG |
563 | on_finish->complete(-ESHUTDOWN); |
564 | return; | |
565 | } | |
566 | ||
567 | Action action(ACTION_TYPE_REFRESH); | |
568 | action.refresh_seq = m_refresh_seq; | |
569 | execute_action_unlock(action, on_finish); | |
570 | } | |
571 | ||
572 | template <typename I> | |
573 | int ImageState<I>::refresh_if_required() { | |
574 | C_SaferCond ctx; | |
575 | { | |
9f95a23c | 576 | m_lock.lock(); |
7c673cae FG |
577 | Action action(ACTION_TYPE_REFRESH); |
578 | action.refresh_seq = m_refresh_seq; | |
579 | ||
580 | auto refresh_action = find_pending_refresh(); | |
581 | if (refresh_action != nullptr) { | |
582 | // if a refresh is in-flight, delay until it is finished | |
583 | action = *refresh_action; | |
584 | } else if (m_last_refresh == m_refresh_seq) { | |
9f95a23c | 585 | m_lock.unlock(); |
7c673cae FG |
586 | return 0; |
587 | } else if (is_closed()) { | |
9f95a23c | 588 | m_lock.unlock(); |
7c673cae FG |
589 | return -ESHUTDOWN; |
590 | } | |
591 | ||
592 | execute_action_unlock(action, &ctx); | |
593 | } | |
594 | ||
595 | return ctx.wait(); | |
596 | } | |
597 | ||
598 | template <typename I> | |
599 | const typename ImageState<I>::Action * | |
600 | ImageState<I>::find_pending_refresh() const { | |
9f95a23c | 601 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
602 | |
603 | auto it = std::find_if(m_actions_contexts.rbegin(), | |
604 | m_actions_contexts.rend(), | |
605 | [](const ActionContexts& action_contexts) { | |
606 | return (action_contexts.first == ACTION_TYPE_REFRESH); | |
607 | }); | |
608 | if (it != m_actions_contexts.rend()) { | |
609 | return &it->first; | |
610 | } | |
611 | return nullptr; | |
612 | } | |
613 | ||
614 | template <typename I> | |
11fdf7f2 | 615 | void ImageState<I>::snap_set(uint64_t snap_id, Context *on_finish) { |
7c673cae | 616 | CephContext *cct = m_image_ctx->cct; |
11fdf7f2 | 617 | ldout(cct, 20) << __func__ << ": snap_id=" << snap_id << dendl; |
7c673cae FG |
618 | |
619 | Action action(ACTION_TYPE_SET_SNAP); | |
11fdf7f2 | 620 | action.snap_id = snap_id; |
7c673cae | 621 | |
9f95a23c | 622 | m_lock.lock(); |
7c673cae FG |
623 | execute_action_unlock(action, on_finish); |
624 | } | |
625 | ||
626 | template <typename I> | |
627 | void ImageState<I>::prepare_lock(Context *on_ready) { | |
628 | CephContext *cct = m_image_ctx->cct; | |
629 | ldout(cct, 10) << __func__ << dendl; | |
630 | ||
9f95a23c | 631 | m_lock.lock(); |
7c673cae | 632 | if (is_closed()) { |
9f95a23c | 633 | m_lock.unlock(); |
7c673cae FG |
634 | on_ready->complete(-ESHUTDOWN); |
635 | return; | |
636 | } | |
637 | ||
638 | Action action(ACTION_TYPE_LOCK); | |
639 | action.on_ready = on_ready; | |
640 | execute_action_unlock(action, nullptr); | |
641 | } | |
642 | ||
643 | template <typename I> | |
644 | void ImageState<I>::handle_prepare_lock_complete() { | |
645 | CephContext *cct = m_image_ctx->cct; | |
646 | ldout(cct, 10) << __func__ << dendl; | |
647 | ||
9f95a23c | 648 | m_lock.lock(); |
7c673cae | 649 | if (m_state != STATE_PREPARING_LOCK) { |
9f95a23c | 650 | m_lock.unlock(); |
7c673cae FG |
651 | return; |
652 | } | |
653 | ||
654 | complete_action_unlock(STATE_OPEN, 0); | |
655 | } | |
656 | ||
657 | template <typename I> | |
658 | int ImageState<I>::register_update_watcher(UpdateWatchCtx *watcher, | |
659 | uint64_t *handle) { | |
660 | CephContext *cct = m_image_ctx->cct; | |
661 | ldout(cct, 20) << __func__ << dendl; | |
662 | ||
663 | m_update_watchers->register_watcher(watcher, handle); | |
664 | ||
665 | ldout(cct, 20) << __func__ << ": handle=" << *handle << dendl; | |
666 | return 0; | |
667 | } | |
668 | ||
669 | template <typename I> | |
9f95a23c TL |
670 | void ImageState<I>::unregister_update_watcher(uint64_t handle, |
671 | Context *on_finish) { | |
7c673cae FG |
672 | CephContext *cct = m_image_ctx->cct; |
673 | ldout(cct, 20) << __func__ << ": handle=" << handle << dendl; | |
674 | ||
9f95a23c TL |
675 | m_update_watchers->unregister_watcher(handle, on_finish); |
676 | } | |
677 | ||
678 | template <typename I> | |
679 | int ImageState<I>::unregister_update_watcher(uint64_t handle) { | |
7c673cae | 680 | C_SaferCond ctx; |
9f95a23c | 681 | unregister_update_watcher(handle, &ctx); |
7c673cae FG |
682 | return ctx.wait(); |
683 | } | |
684 | ||
685 | template <typename I> | |
686 | void ImageState<I>::flush_update_watchers(Context *on_finish) { | |
687 | CephContext *cct = m_image_ctx->cct; | |
688 | ldout(cct, 20) << __func__ << dendl; | |
689 | ||
690 | m_update_watchers->flush(on_finish); | |
691 | } | |
692 | ||
693 | template <typename I> | |
694 | void ImageState<I>::shut_down_update_watchers(Context *on_finish) { | |
695 | CephContext *cct = m_image_ctx->cct; | |
696 | ldout(cct, 20) << __func__ << dendl; | |
697 | ||
698 | m_update_watchers->shut_down(on_finish); | |
699 | } | |
700 | ||
701 | template <typename I> | |
702 | bool ImageState<I>::is_transition_state() const { | |
703 | switch (m_state) { | |
704 | case STATE_UNINITIALIZED: | |
705 | case STATE_OPEN: | |
706 | case STATE_CLOSED: | |
707 | return false; | |
708 | case STATE_OPENING: | |
709 | case STATE_CLOSING: | |
710 | case STATE_REFRESHING: | |
711 | case STATE_SETTING_SNAP: | |
712 | case STATE_PREPARING_LOCK: | |
713 | break; | |
714 | } | |
715 | return true; | |
716 | } | |
717 | ||
718 | template <typename I> | |
719 | bool ImageState<I>::is_closed() const { | |
9f95a23c | 720 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
721 | |
722 | return ((m_state == STATE_CLOSED) || | |
723 | (!m_actions_contexts.empty() && | |
724 | m_actions_contexts.back().first.action_type == ACTION_TYPE_CLOSE)); | |
725 | } | |
726 | ||
727 | template <typename I> | |
728 | void ImageState<I>::append_context(const Action &action, Context *context) { | |
9f95a23c | 729 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
730 | |
731 | ActionContexts *action_contexts = nullptr; | |
732 | for (auto &action_ctxs : m_actions_contexts) { | |
733 | if (action == action_ctxs.first) { | |
734 | action_contexts = &action_ctxs; | |
735 | break; | |
736 | } | |
737 | } | |
738 | ||
739 | if (action_contexts == nullptr) { | |
740 | m_actions_contexts.push_back({action, {}}); | |
741 | action_contexts = &m_actions_contexts.back(); | |
742 | } | |
743 | ||
744 | if (context != nullptr) { | |
745 | action_contexts->second.push_back(context); | |
746 | } | |
747 | } | |
748 | ||
749 | template <typename I> | |
750 | void ImageState<I>::execute_next_action_unlock() { | |
9f95a23c | 751 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
11fdf7f2 | 752 | ceph_assert(!m_actions_contexts.empty()); |
7c673cae FG |
753 | switch (m_actions_contexts.front().first.action_type) { |
754 | case ACTION_TYPE_OPEN: | |
755 | send_open_unlock(); | |
756 | return; | |
757 | case ACTION_TYPE_CLOSE: | |
758 | send_close_unlock(); | |
759 | return; | |
760 | case ACTION_TYPE_REFRESH: | |
761 | send_refresh_unlock(); | |
762 | return; | |
763 | case ACTION_TYPE_SET_SNAP: | |
764 | send_set_snap_unlock(); | |
765 | return; | |
766 | case ACTION_TYPE_LOCK: | |
767 | send_prepare_lock_unlock(); | |
768 | return; | |
769 | } | |
11fdf7f2 | 770 | ceph_abort(); |
7c673cae FG |
771 | } |
772 | ||
773 | template <typename I> | |
774 | void ImageState<I>::execute_action_unlock(const Action &action, | |
775 | Context *on_finish) { | |
9f95a23c | 776 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
777 | |
778 | append_context(action, on_finish); | |
779 | if (!is_transition_state()) { | |
780 | execute_next_action_unlock(); | |
781 | } else { | |
9f95a23c | 782 | m_lock.unlock(); |
7c673cae FG |
783 | } |
784 | } | |
785 | ||
786 | template <typename I> | |
787 | void ImageState<I>::complete_action_unlock(State next_state, int r) { | |
9f95a23c | 788 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
11fdf7f2 | 789 | ceph_assert(!m_actions_contexts.empty()); |
7c673cae FG |
790 | |
791 | ActionContexts action_contexts(std::move(m_actions_contexts.front())); | |
792 | m_actions_contexts.pop_front(); | |
793 | ||
794 | m_state = next_state; | |
9f95a23c | 795 | m_lock.unlock(); |
7c673cae | 796 | |
f67539c2 TL |
797 | if (next_state == STATE_CLOSED || |
798 | (next_state == STATE_UNINITIALIZED && r < 0)) { | |
799 | // the ImageCtx must be deleted outside the scope of its callback threads | |
800 | auto ctx = new LambdaContext( | |
801 | [image_ctx=m_image_ctx, contexts=std::move(action_contexts.second)] | |
802 | (int r) { | |
803 | delete image_ctx; | |
804 | for (auto ctx : contexts) { | |
805 | ctx->complete(r); | |
806 | } | |
807 | }); | |
808 | TaskFinisherSingleton::get_singleton(m_image_ctx->cct).queue(ctx, r); | |
809 | } else { | |
810 | for (auto ctx : action_contexts.second) { | |
811 | if (next_state == STATE_OPEN) { | |
812 | // we couldn't originally wrap the open callback w/ an async wrapper in | |
813 | // case the image failed to open | |
814 | ctx = create_async_context_callback(*m_image_ctx, ctx); | |
815 | } | |
816 | ctx->complete(r); | |
817 | } | |
7c673cae | 818 | |
9f95a23c | 819 | m_lock.lock(); |
7c673cae FG |
820 | if (!is_transition_state() && !m_actions_contexts.empty()) { |
821 | execute_next_action_unlock(); | |
822 | } else { | |
9f95a23c | 823 | m_lock.unlock(); |
7c673cae FG |
824 | } |
825 | } | |
826 | } | |
827 | ||
828 | template <typename I> | |
829 | void ImageState<I>::send_open_unlock() { | |
9f95a23c | 830 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
831 | CephContext *cct = m_image_ctx->cct; |
832 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
833 | ||
834 | m_state = STATE_OPENING; | |
835 | ||
f67539c2 TL |
836 | Context *ctx = create_context_callback< |
837 | ImageState<I>, &ImageState<I>::handle_open>(this); | |
7c673cae | 838 | image::OpenRequest<I> *req = image::OpenRequest<I>::create( |
11fdf7f2 | 839 | m_image_ctx, m_open_flags, ctx); |
7c673cae | 840 | |
9f95a23c | 841 | m_lock.unlock(); |
7c673cae FG |
842 | req->send(); |
843 | } | |
844 | ||
845 | template <typename I> | |
846 | void ImageState<I>::handle_open(int r) { | |
847 | CephContext *cct = m_image_ctx->cct; | |
848 | ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; | |
849 | ||
850 | if (r < 0 && r != -ENOENT) { | |
851 | lderr(cct) << "failed to open image: " << cpp_strerror(r) << dendl; | |
852 | } | |
853 | ||
9f95a23c | 854 | m_lock.lock(); |
7c673cae FG |
855 | complete_action_unlock(r < 0 ? STATE_UNINITIALIZED : STATE_OPEN, r); |
856 | } | |
857 | ||
858 | template <typename I> | |
859 | void ImageState<I>::send_close_unlock() { | |
9f95a23c | 860 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
861 | CephContext *cct = m_image_ctx->cct; |
862 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
863 | ||
864 | m_state = STATE_CLOSING; | |
865 | ||
866 | Context *ctx = create_context_callback< | |
867 | ImageState<I>, &ImageState<I>::handle_close>(this); | |
868 | image::CloseRequest<I> *req = image::CloseRequest<I>::create( | |
869 | m_image_ctx, ctx); | |
870 | ||
9f95a23c | 871 | m_lock.unlock(); |
7c673cae FG |
872 | req->send(); |
873 | } | |
874 | ||
875 | template <typename I> | |
876 | void ImageState<I>::handle_close(int r) { | |
877 | CephContext *cct = m_image_ctx->cct; | |
878 | ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; | |
879 | ||
880 | if (r < 0) { | |
881 | lderr(cct) << "error occurred while closing image: " << cpp_strerror(r) | |
882 | << dendl; | |
883 | } | |
884 | ||
9f95a23c | 885 | m_lock.lock(); |
7c673cae FG |
886 | complete_action_unlock(STATE_CLOSED, r); |
887 | } | |
888 | ||
889 | template <typename I> | |
890 | void ImageState<I>::send_refresh_unlock() { | |
9f95a23c | 891 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
892 | CephContext *cct = m_image_ctx->cct; |
893 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
894 | ||
895 | m_state = STATE_REFRESHING; | |
11fdf7f2 | 896 | ceph_assert(!m_actions_contexts.empty()); |
7c673cae | 897 | auto &action_context = m_actions_contexts.front().first; |
11fdf7f2 | 898 | ceph_assert(action_context.action_type == ACTION_TYPE_REFRESH); |
7c673cae FG |
899 | |
900 | Context *ctx = create_async_context_callback( | |
901 | *m_image_ctx, create_context_callback< | |
902 | ImageState<I>, &ImageState<I>::handle_refresh>(this)); | |
903 | image::RefreshRequest<I> *req = image::RefreshRequest<I>::create( | |
904 | *m_image_ctx, false, false, ctx); | |
905 | ||
9f95a23c | 906 | m_lock.unlock(); |
7c673cae FG |
907 | req->send(); |
908 | } | |
909 | ||
910 | template <typename I> | |
911 | void ImageState<I>::handle_refresh(int r) { | |
912 | CephContext *cct = m_image_ctx->cct; | |
913 | ldout(cct, 10) << this << " " << __func__ << ": r=" << r << dendl; | |
914 | ||
9f95a23c | 915 | m_lock.lock(); |
11fdf7f2 | 916 | ceph_assert(!m_actions_contexts.empty()); |
7c673cae FG |
917 | |
918 | ActionContexts &action_contexts(m_actions_contexts.front()); | |
11fdf7f2 TL |
919 | ceph_assert(action_contexts.first.action_type == ACTION_TYPE_REFRESH); |
920 | ceph_assert(m_last_refresh <= action_contexts.first.refresh_seq); | |
7c673cae FG |
921 | |
922 | if (r == -ERESTART) { | |
923 | ldout(cct, 5) << "incomplete refresh: not updating sequence" << dendl; | |
924 | r = 0; | |
925 | } else { | |
926 | m_last_refresh = action_contexts.first.refresh_seq; | |
927 | } | |
928 | ||
929 | complete_action_unlock(STATE_OPEN, r); | |
930 | } | |
931 | ||
932 | template <typename I> | |
933 | void ImageState<I>::send_set_snap_unlock() { | |
9f95a23c | 934 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
935 | |
936 | m_state = STATE_SETTING_SNAP; | |
937 | ||
11fdf7f2 | 938 | ceph_assert(!m_actions_contexts.empty()); |
7c673cae | 939 | ActionContexts &action_contexts(m_actions_contexts.front()); |
11fdf7f2 | 940 | ceph_assert(action_contexts.first.action_type == ACTION_TYPE_SET_SNAP); |
7c673cae FG |
941 | |
942 | CephContext *cct = m_image_ctx->cct; | |
943 | ldout(cct, 10) << this << " " << __func__ << ": " | |
11fdf7f2 | 944 | << "snap_id=" << action_contexts.first.snap_id << dendl; |
7c673cae FG |
945 | |
946 | Context *ctx = create_async_context_callback( | |
947 | *m_image_ctx, create_context_callback< | |
948 | ImageState<I>, &ImageState<I>::handle_set_snap>(this)); | |
949 | image::SetSnapRequest<I> *req = image::SetSnapRequest<I>::create( | |
11fdf7f2 | 950 | *m_image_ctx, action_contexts.first.snap_id, ctx); |
7c673cae | 951 | |
9f95a23c | 952 | m_lock.unlock(); |
7c673cae FG |
953 | req->send(); |
954 | } | |
955 | ||
956 | template <typename I> | |
957 | void ImageState<I>::handle_set_snap(int r) { | |
958 | CephContext *cct = m_image_ctx->cct; | |
959 | ldout(cct, 10) << this << " " << __func__ << " r=" << r << dendl; | |
960 | ||
961 | if (r < 0 && r != -ENOENT) { | |
962 | lderr(cct) << "failed to set snapshot: " << cpp_strerror(r) << dendl; | |
963 | } | |
964 | ||
9f95a23c | 965 | m_lock.lock(); |
7c673cae FG |
966 | complete_action_unlock(STATE_OPEN, r); |
967 | } | |
968 | ||
969 | template <typename I> | |
970 | void ImageState<I>::send_prepare_lock_unlock() { | |
971 | CephContext *cct = m_image_ctx->cct; | |
972 | ldout(cct, 10) << this << " " << __func__ << dendl; | |
973 | ||
9f95a23c | 974 | ceph_assert(ceph_mutex_is_locked(m_lock)); |
7c673cae FG |
975 | m_state = STATE_PREPARING_LOCK; |
976 | ||
11fdf7f2 | 977 | ceph_assert(!m_actions_contexts.empty()); |
7c673cae | 978 | ActionContexts &action_contexts(m_actions_contexts.front()); |
11fdf7f2 | 979 | ceph_assert(action_contexts.first.action_type == ACTION_TYPE_LOCK); |
7c673cae FG |
980 | |
981 | Context *on_ready = action_contexts.first.on_ready; | |
9f95a23c | 982 | m_lock.unlock(); |
7c673cae FG |
983 | |
984 | if (on_ready == nullptr) { | |
985 | complete_action_unlock(STATE_OPEN, 0); | |
986 | return; | |
987 | } | |
988 | ||
989 | // wake up the lock handler now that its safe to proceed | |
990 | on_ready->complete(0); | |
991 | } | |
992 | ||
f67539c2 TL |
993 | template <typename I> |
994 | int ImageState<I>::register_quiesce_watcher(QuiesceWatchCtx *watcher, | |
995 | uint64_t *handle) { | |
996 | CephContext *cct = m_image_ctx->cct; | |
997 | ldout(cct, 20) << __func__ << dendl; | |
998 | ||
999 | m_quiesce_watchers->register_watcher(watcher, handle); | |
1000 | ||
1001 | ldout(cct, 20) << __func__ << ": handle=" << *handle << dendl; | |
1002 | return 0; | |
1003 | } | |
1004 | ||
1005 | template <typename I> | |
1006 | int ImageState<I>::unregister_quiesce_watcher(uint64_t handle) { | |
1007 | CephContext *cct = m_image_ctx->cct; | |
1008 | ldout(cct, 20) << __func__ << ": handle=" << handle << dendl; | |
1009 | ||
1010 | C_SaferCond ctx; | |
1011 | m_quiesce_watchers->unregister_watcher(handle, &ctx); | |
1012 | return ctx.wait(); | |
1013 | } | |
1014 | ||
1015 | template <typename I> | |
1016 | void ImageState<I>::notify_quiesce(Context *on_finish) { | |
1017 | CephContext *cct = m_image_ctx->cct; | |
1018 | ldout(cct, 20) << __func__ << dendl; | |
1019 | ||
1020 | m_quiesce_watchers->notify_quiesce(on_finish); | |
1021 | } | |
1022 | ||
1023 | template <typename I> | |
1024 | void ImageState<I>::notify_unquiesce(Context *on_finish) { | |
1025 | CephContext *cct = m_image_ctx->cct; | |
1026 | ldout(cct, 20) << __func__ << dendl; | |
1027 | ||
1028 | m_quiesce_watchers->notify_unquiesce(on_finish); | |
1029 | } | |
1030 | ||
1031 | template <typename I> | |
1032 | void ImageState<I>::quiesce_complete(uint64_t handle, int r) { | |
1033 | CephContext *cct = m_image_ctx->cct; | |
1034 | ldout(cct, 20) << __func__ << ": handle=" << handle << " r=" << r << dendl; | |
1035 | m_quiesce_watchers->quiesce_complete(handle, r); | |
1036 | } | |
1037 | ||
7c673cae FG |
1038 | } // namespace librbd |
1039 | ||
1040 | template class librbd::ImageState<librbd::ImageCtx>; |