Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / librbd / ExclusiveLock.cc
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/ExclusiveLock.h"
5 #include "librbd/ImageCtx.h"
6 #include "librbd/ImageWatcher.h"
7 #include "librbd/ImageState.h"
8 #include "librbd/exclusive_lock/PreAcquireRequest.h"
9 #include "librbd/exclusive_lock/PostAcquireRequest.h"
10 #include "librbd/exclusive_lock/PreReleaseRequest.h"
11 #include "librbd/io/ImageRequestWQ.h"
12 #include "librbd/Utils.h"
13 #include "common/Mutex.h"
14 #include "common/dout.h"
15
16 #define dout_subsys ceph_subsys_rbd
17 #undef dout_prefix
18 #define dout_prefix *_dout << "librbd::ExclusiveLock: " << this << " " \
19                            <<  __func__
20
21 namespace librbd {
22
23 using namespace exclusive_lock;
24
25 template <typename I>
26 using ML = ManagedLock<I>;
27
28 template <typename I>
29 ExclusiveLock<I>::ExclusiveLock(I &image_ctx)
30   : ML<I>(image_ctx.md_ctx, image_ctx.op_work_queue, image_ctx.header_oid,
31           image_ctx.image_watcher, managed_lock::EXCLUSIVE,
32           image_ctx.blacklist_on_break_lock,
33           image_ctx.blacklist_expire_seconds),
34     m_image_ctx(image_ctx) {
35   Mutex::Locker locker(ML<I>::m_lock);
36   ML<I>::set_state_uninitialized();
37 }
38
39 template <typename I>
40 bool ExclusiveLock<I>::accept_requests(int *ret_val) const {
41   Mutex::Locker locker(ML<I>::m_lock);
42
43   bool accept_requests = (!ML<I>::is_state_shutdown() &&
44                           ML<I>::is_state_locked() &&
45                           m_request_blocked_count == 0);
46   if (ret_val != nullptr) {
47     *ret_val = m_request_blocked_ret_val;
48   }
49
50   ldout(m_image_ctx.cct, 20) << "=" << accept_requests << dendl;
51   return accept_requests;
52 }
53
54 template <typename I>
55 bool ExclusiveLock<I>::accept_ops() const {
56   Mutex::Locker locker(ML<I>::m_lock);
57   bool accept = accept_ops(ML<I>::m_lock);
58   ldout(m_image_ctx.cct, 20) << "=" << accept << dendl;
59   return accept;
60 }
61
62 template <typename I>
63 bool ExclusiveLock<I>::accept_ops(const Mutex &lock) const {
64   return (!ML<I>::is_state_shutdown() &&
65           (ML<I>::is_state_locked() || ML<I>::is_state_post_acquiring()));
66 }
67
68 template <typename I>
69 void ExclusiveLock<I>::block_requests(int r) {
70   Mutex::Locker locker(ML<I>::m_lock);
71
72   m_request_blocked_count++;
73   if (m_request_blocked_ret_val == 0) {
74     m_request_blocked_ret_val = r;
75   }
76
77   ldout(m_image_ctx.cct, 20) << dendl;
78 }
79
80 template <typename I>
81 void ExclusiveLock<I>::unblock_requests() {
82   Mutex::Locker locker(ML<I>::m_lock);
83
84   assert(m_request_blocked_count > 0);
85   m_request_blocked_count--;
86   if (m_request_blocked_count == 0) {
87     m_request_blocked_ret_val = 0;
88   }
89
90   ldout(m_image_ctx.cct, 20) << dendl;
91 }
92
93 template <typename I>
94 void ExclusiveLock<I>::init(uint64_t features, Context *on_init) {
95   assert(m_image_ctx.owner_lock.is_locked());
96   ldout(m_image_ctx.cct, 10) << dendl;
97
98   {
99     Mutex::Locker locker(ML<I>::m_lock);
100     ML<I>::set_state_initializing();
101   }
102
103   m_image_ctx.io_work_queue->block_writes(new C_InitComplete(this, features,
104                                                              on_init));
105 }
106
107 template <typename I>
108 void ExclusiveLock<I>::shut_down(Context *on_shut_down) {
109   ldout(m_image_ctx.cct, 10) << dendl;
110
111   ML<I>::shut_down(on_shut_down);
112
113   // if stalled in request state machine -- abort
114   handle_peer_notification(0);
115 }
116
117 template <typename I>
118 void ExclusiveLock<I>::handle_peer_notification(int r) {
119   Mutex::Locker locker(ML<I>::m_lock);
120   if (!ML<I>::is_state_waiting_for_lock()) {
121     return;
122   }
123
124   ldout(m_image_ctx.cct, 10) << dendl;
125   assert(ML<I>::is_action_acquire_lock());
126
127   m_acquire_lock_peer_ret_val = r;
128   ML<I>::execute_next_action();
129 }
130
131 template <typename I>
132 Context *ExclusiveLock<I>::start_op() {
133   assert(m_image_ctx.owner_lock.is_locked());
134   Mutex::Locker locker(ML<I>::m_lock);
135
136   if (!accept_ops(ML<I>::m_lock)) {
137     return nullptr;
138   }
139
140   m_async_op_tracker.start_op();
141   return new FunctionContext([this](int r) {
142       m_async_op_tracker.finish_op();
143     });
144 }
145
146 template <typename I>
147 void ExclusiveLock<I>::handle_init_complete(uint64_t features) {
148   ldout(m_image_ctx.cct, 10) << ": features=" << features << dendl;
149
150   {
151     RWLock::RLocker owner_locker(m_image_ctx.owner_lock);
152     if (m_image_ctx.clone_copy_on_read ||
153         (features & RBD_FEATURE_JOURNALING) != 0) {
154       m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_BOTH, true);
155     } else {
156       m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_WRITE, true);
157     }
158   }
159
160   Mutex::Locker locker(ML<I>::m_lock);
161   ML<I>::set_state_unlocked();
162 }
163
164 template <typename I>
165 void ExclusiveLock<I>::shutdown_handler(int r, Context *on_finish) {
166   ldout(m_image_ctx.cct, 10) << dendl;
167
168   {
169     RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
170     m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_BOTH, false);
171     m_image_ctx.exclusive_lock = nullptr;
172   }
173
174   m_image_ctx.io_work_queue->unblock_writes();
175   m_image_ctx.image_watcher->flush(on_finish);
176 }
177
178 template <typename I>
179 void ExclusiveLock<I>::pre_acquire_lock_handler(Context *on_finish) {
180   ldout(m_image_ctx.cct, 10) << dendl;
181
182   int acquire_lock_peer_ret_val = 0;
183   {
184     Mutex::Locker locker(ML<I>::m_lock);
185     std::swap(acquire_lock_peer_ret_val, m_acquire_lock_peer_ret_val);
186   }
187
188   if (acquire_lock_peer_ret_val == -EROFS) {
189     ldout(m_image_ctx.cct, 10) << ": peer nacked lock request" << dendl;
190     on_finish->complete(acquire_lock_peer_ret_val);
191     return;
192   }
193
194   PreAcquireRequest<I> *req = PreAcquireRequest<I>::create(m_image_ctx,
195                                                            on_finish);
196   m_image_ctx.op_work_queue->queue(new FunctionContext([req](int r) {
197     req->send();
198   }));
199 }
200
201 template <typename I>
202 void ExclusiveLock<I>::post_acquire_lock_handler(int r, Context *on_finish) {
203   ldout(m_image_ctx.cct, 10) << ": r=" << r << dendl;
204
205   if (r == -EROFS) {
206     // peer refused to release the exclusive lock
207     on_finish->complete(r);
208     return;
209   } else if (r < 0) {
210     ML<I>::m_lock.Lock();
211     assert(ML<I>::is_state_acquiring());
212
213     // PostAcquire state machine will not run, so we need complete prepare
214     m_image_ctx.state->handle_prepare_lock_complete();
215
216     // if lock is in-use by another client, request the lock
217     if (ML<I>::is_action_acquire_lock() && (r == -EBUSY || r == -EAGAIN)) {
218       ML<I>::set_state_waiting_for_lock();
219       ML<I>::m_lock.Unlock();
220
221       // request the lock from a peer
222       m_image_ctx.image_watcher->notify_request_lock();
223
224       // inform manage lock that we have interrupted the state machine
225       r = -ECANCELED;
226     } else {
227       ML<I>::m_lock.Unlock();
228
229       // clear error if peer owns lock
230       if (r == -EAGAIN) {
231         r = 0;
232       }
233     }
234
235     on_finish->complete(r);
236     return;
237   }
238
239   Mutex::Locker locker(ML<I>::m_lock);
240   m_pre_post_callback = on_finish;
241   using EL = ExclusiveLock<I>;
242   PostAcquireRequest<I> *req = PostAcquireRequest<I>::create(m_image_ctx,
243       util::create_context_callback<EL, &EL::handle_post_acquiring_lock>(this),
244       util::create_context_callback<EL, &EL::handle_post_acquired_lock>(this));
245
246   m_image_ctx.op_work_queue->queue(new FunctionContext([req](int r) {
247     req->send();
248   }));
249 }
250
251 template <typename I>
252 void ExclusiveLock<I>::handle_post_acquiring_lock(int r) {
253   ldout(m_image_ctx.cct, 10) << dendl;
254
255   Mutex::Locker locker(ML<I>::m_lock);
256
257   assert(r == 0);
258
259   // lock is owned at this point
260   ML<I>::set_state_post_acquiring();
261 }
262
263 template <typename I>
264 void ExclusiveLock<I>::handle_post_acquired_lock(int r) {
265   ldout(m_image_ctx.cct, 10) << ": r=" << r << dendl;
266
267   Context *on_finish = nullptr;
268   {
269     Mutex::Locker locker(ML<I>::m_lock);
270     assert(ML<I>::is_state_acquiring() || ML<I>::is_state_post_acquiring());
271
272     assert (m_pre_post_callback != nullptr);
273     std::swap(m_pre_post_callback, on_finish);
274   }
275
276   if (r >= 0) {
277     m_image_ctx.image_watcher->notify_acquired_lock();
278     m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_BOTH, false);
279     m_image_ctx.io_work_queue->unblock_writes();
280   }
281
282   on_finish->complete(r);
283 }
284
285 template <typename I>
286 void ExclusiveLock<I>::pre_release_lock_handler(bool shutting_down,
287                                                 Context *on_finish) {
288   ldout(m_image_ctx.cct, 10) << dendl;
289   Mutex::Locker locker(ML<I>::m_lock);
290
291   PreReleaseRequest<I> *req = PreReleaseRequest<I>::create(
292     m_image_ctx, shutting_down, m_async_op_tracker, on_finish);
293   m_image_ctx.op_work_queue->queue(new FunctionContext([req](int r) {
294     req->send();
295   }));
296 }
297
298 template <typename I>
299 void ExclusiveLock<I>::post_release_lock_handler(bool shutting_down, int r,
300                                                  Context *on_finish) {
301   ldout(m_image_ctx.cct, 10) << ": r=" << r << " shutting_down="
302                              << shutting_down << dendl;
303   if (!shutting_down) {
304     {
305       Mutex::Locker locker(ML<I>::m_lock);
306       assert(ML<I>::is_state_pre_releasing() || ML<I>::is_state_releasing());
307     }
308
309     if (r >= 0) {
310       m_image_ctx.image_watcher->notify_released_lock();
311     }
312   } else {
313     {
314       RWLock::WLocker owner_locker(m_image_ctx.owner_lock);
315       m_image_ctx.io_work_queue->set_require_lock(io::DIRECTION_BOTH, false);
316       m_image_ctx.exclusive_lock = nullptr;
317     }
318
319     if (r >= 0) {
320       m_image_ctx.io_work_queue->unblock_writes();
321     }
322
323     m_image_ctx.image_watcher->notify_released_lock();
324   }
325
326   on_finish->complete(r);
327 }
328
329 template <typename I>
330 void ExclusiveLock<I>::post_reacquire_lock_handler(int r, Context *on_finish) {
331   ldout(m_image_ctx.cct, 10) << dendl;
332   if (r >= 0) {
333     m_image_ctx.image_watcher->notify_acquired_lock();
334   }
335
336   on_finish->complete(r);
337 }
338
339 template <typename I>
340 struct ExclusiveLock<I>::C_InitComplete : public Context {
341   ExclusiveLock *exclusive_lock;
342   uint64_t features;
343   Context *on_init;
344
345   C_InitComplete(ExclusiveLock *exclusive_lock, uint64_t features,
346                  Context *on_init)
347     : exclusive_lock(exclusive_lock), features(features), on_init(on_init) {
348   }
349   void finish(int r) override {
350     if (r == 0) {
351       exclusive_lock->handle_init_complete(features);
352     }
353     on_init->complete(r);
354   }
355 };
356
357 } // namespace librbd
358
359 template class librbd::ExclusiveLock<librbd::ImageCtx>;