1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
16 #define dout_subsys ceph_subsys_rbd
18 #define dout_prefix *_dout << "librbd::ExclusiveLock: " << this << " " \
23 using namespace exclusive_lock
;
26 using ML
= ManagedLock
<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();
40 bool ExclusiveLock
<I
>::accept_requests(int *ret_val
) const {
41 Mutex::Locker
locker(ML
<I
>::m_lock
);
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
;
50 ldout(m_image_ctx
.cct
, 20) << "=" << accept_requests
<< dendl
;
51 return accept_requests
;
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
;
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()));
69 void ExclusiveLock
<I
>::block_requests(int r
) {
70 Mutex::Locker
locker(ML
<I
>::m_lock
);
72 m_request_blocked_count
++;
73 if (m_request_blocked_ret_val
== 0) {
74 m_request_blocked_ret_val
= r
;
77 ldout(m_image_ctx
.cct
, 20) << dendl
;
81 void ExclusiveLock
<I
>::unblock_requests() {
82 Mutex::Locker
locker(ML
<I
>::m_lock
);
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;
90 ldout(m_image_ctx
.cct
, 20) << dendl
;
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
;
99 Mutex::Locker
locker(ML
<I
>::m_lock
);
100 ML
<I
>::set_state_initializing();
103 m_image_ctx
.io_work_queue
->block_writes(new C_InitComplete(this, features
,
107 template <typename I
>
108 void ExclusiveLock
<I
>::shut_down(Context
*on_shut_down
) {
109 ldout(m_image_ctx
.cct
, 10) << dendl
;
111 ML
<I
>::shut_down(on_shut_down
);
113 // if stalled in request state machine -- abort
114 handle_peer_notification(0);
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()) {
124 ldout(m_image_ctx
.cct
, 10) << dendl
;
125 assert(ML
<I
>::is_action_acquire_lock());
127 m_acquire_lock_peer_ret_val
= r
;
128 ML
<I
>::execute_next_action();
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
);
136 if (!accept_ops(ML
<I
>::m_lock
)) {
140 m_async_op_tracker
.start_op();
141 return new FunctionContext([this](int r
) {
142 m_async_op_tracker
.finish_op();
146 template <typename I
>
147 void ExclusiveLock
<I
>::handle_init_complete(uint64_t features
) {
148 ldout(m_image_ctx
.cct
, 10) << ": features=" << features
<< dendl
;
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);
156 m_image_ctx
.io_work_queue
->set_require_lock(io::DIRECTION_WRITE
, true);
160 Mutex::Locker
locker(ML
<I
>::m_lock
);
161 ML
<I
>::set_state_unlocked();
164 template <typename I
>
165 void ExclusiveLock
<I
>::shutdown_handler(int r
, Context
*on_finish
) {
166 ldout(m_image_ctx
.cct
, 10) << dendl
;
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;
174 m_image_ctx
.io_work_queue
->unblock_writes();
175 m_image_ctx
.image_watcher
->flush(on_finish
);
178 template <typename I
>
179 void ExclusiveLock
<I
>::pre_acquire_lock_handler(Context
*on_finish
) {
180 ldout(m_image_ctx
.cct
, 10) << dendl
;
182 int acquire_lock_peer_ret_val
= 0;
184 Mutex::Locker
locker(ML
<I
>::m_lock
);
185 std::swap(acquire_lock_peer_ret_val
, m_acquire_lock_peer_ret_val
);
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
);
194 PreAcquireRequest
<I
> *req
= PreAcquireRequest
<I
>::create(m_image_ctx
,
196 m_image_ctx
.op_work_queue
->queue(new FunctionContext([req
](int r
) {
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
;
206 // peer refused to release the exclusive lock
207 on_finish
->complete(r
);
210 ML
<I
>::m_lock
.Lock();
211 assert(ML
<I
>::is_state_acquiring());
213 // PostAcquire state machine will not run, so we need complete prepare
214 m_image_ctx
.state
->handle_prepare_lock_complete();
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();
221 // request the lock from a peer
222 m_image_ctx
.image_watcher
->notify_request_lock();
224 // inform manage lock that we have interrupted the state machine
227 ML
<I
>::m_lock
.Unlock();
229 // clear error if peer owns lock
235 on_finish
->complete(r
);
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));
246 m_image_ctx
.op_work_queue
->queue(new FunctionContext([req
](int r
) {
251 template <typename I
>
252 void ExclusiveLock
<I
>::handle_post_acquiring_lock(int r
) {
253 ldout(m_image_ctx
.cct
, 10) << dendl
;
255 Mutex::Locker
locker(ML
<I
>::m_lock
);
259 // lock is owned at this point
260 ML
<I
>::set_state_post_acquiring();
263 template <typename I
>
264 void ExclusiveLock
<I
>::handle_post_acquired_lock(int r
) {
265 ldout(m_image_ctx
.cct
, 10) << ": r=" << r
<< dendl
;
267 Context
*on_finish
= nullptr;
269 Mutex::Locker
locker(ML
<I
>::m_lock
);
270 assert(ML
<I
>::is_state_acquiring() || ML
<I
>::is_state_post_acquiring());
272 assert (m_pre_post_callback
!= nullptr);
273 std::swap(m_pre_post_callback
, on_finish
);
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();
282 on_finish
->complete(r
);
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
);
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
) {
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
) {
305 Mutex::Locker
locker(ML
<I
>::m_lock
);
306 assert(ML
<I
>::is_state_pre_releasing() || ML
<I
>::is_state_releasing());
310 m_image_ctx
.image_watcher
->notify_released_lock();
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;
320 m_image_ctx
.io_work_queue
->unblock_writes();
323 m_image_ctx
.image_watcher
->notify_released_lock();
326 on_finish
->complete(r
);
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
;
333 m_image_ctx
.image_watcher
->notify_acquired_lock();
336 on_finish
->complete(r
);
339 template <typename I
>
340 struct ExclusiveLock
<I
>::C_InitComplete
: public Context
{
341 ExclusiveLock
*exclusive_lock
;
345 C_InitComplete(ExclusiveLock
*exclusive_lock
, uint64_t features
,
347 : exclusive_lock(exclusive_lock
), features(features
), on_init(on_init
) {
349 void finish(int r
) override
{
351 exclusive_lock
->handle_init_complete(features
);
353 on_init
->complete(r
);
357 } // namespace librbd
359 template class librbd::ExclusiveLock
<librbd::ImageCtx
>;