1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/exclusive_lock/PreReleaseRequest.h"
5 #include "common/AsyncOpTracker.h"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "librbd/ExclusiveLock.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/ImageWatcher.h"
11 #include "librbd/Journal.h"
12 #include "librbd/ObjectMap.h"
13 #include "librbd/Utils.h"
14 #include "librbd/io/ImageRequestWQ.h"
16 #define dout_subsys ceph_subsys_rbd
18 #define dout_prefix *_dout << "librbd::exclusive_lock::PreReleaseRequest: " \
19 << this << " " << __func__ << ": "
22 namespace exclusive_lock
{
24 using util::create_async_context_callback
;
25 using util::create_context_callback
;
28 PreReleaseRequest
<I
>* PreReleaseRequest
<I
>::create(
29 I
&image_ctx
, bool shutting_down
, AsyncOpTracker
&async_op_tracker
,
31 return new PreReleaseRequest(image_ctx
, shutting_down
, async_op_tracker
,
36 PreReleaseRequest
<I
>::PreReleaseRequest(I
&image_ctx
, bool shutting_down
,
37 AsyncOpTracker
&async_op_tracker
,
39 : m_image_ctx(image_ctx
), m_shutting_down(shutting_down
),
40 m_async_op_tracker(async_op_tracker
),
41 m_on_finish(create_async_context_callback(image_ctx
, on_finish
)) {
45 PreReleaseRequest
<I
>::~PreReleaseRequest() {
46 if (!m_shutting_down
) {
47 m_image_ctx
.state
->handle_prepare_lock_complete();
52 void PreReleaseRequest
<I
>::send() {
57 void PreReleaseRequest
<I
>::send_prepare_lock() {
58 if (m_shutting_down
) {
59 send_cancel_op_requests();
63 CephContext
*cct
= m_image_ctx
.cct
;
64 ldout(cct
, 10) << dendl
;
66 // release the lock if the image is not busy performing other actions
67 Context
*ctx
= create_context_callback
<
68 PreReleaseRequest
<I
>, &PreReleaseRequest
<I
>::handle_prepare_lock
>(this);
69 m_image_ctx
.state
->prepare_lock(ctx
);
73 void PreReleaseRequest
<I
>::handle_prepare_lock(int r
) {
74 CephContext
*cct
= m_image_ctx
.cct
;
75 ldout(cct
, 10) << "r=" << r
<< dendl
;
77 send_cancel_op_requests();
81 void PreReleaseRequest
<I
>::send_cancel_op_requests() {
82 CephContext
*cct
= m_image_ctx
.cct
;
83 ldout(cct
, 10) << dendl
;
85 using klass
= PreReleaseRequest
<I
>;
86 Context
*ctx
= create_context_callback
<
87 klass
, &klass::handle_cancel_op_requests
>(this);
88 m_image_ctx
.cancel_async_requests(ctx
);
92 void PreReleaseRequest
<I
>::handle_cancel_op_requests(int r
) {
93 CephContext
*cct
= m_image_ctx
.cct
;
94 ldout(cct
, 10) << "r=" << r
<< dendl
;
101 template <typename I
>
102 void PreReleaseRequest
<I
>::send_block_writes() {
103 CephContext
*cct
= m_image_ctx
.cct
;
104 ldout(cct
, 10) << dendl
;
106 using klass
= PreReleaseRequest
<I
>;
107 Context
*ctx
= create_context_callback
<
108 klass
, &klass::handle_block_writes
>(this);
111 RWLock::RLocker
owner_locker(m_image_ctx
.owner_lock
);
112 if (m_image_ctx
.test_features(RBD_FEATURE_JOURNALING
)) {
113 m_image_ctx
.io_work_queue
->set_require_lock_on_read();
115 m_image_ctx
.io_work_queue
->block_writes(ctx
);
119 template <typename I
>
120 void PreReleaseRequest
<I
>::handle_block_writes(int r
) {
121 CephContext
*cct
= m_image_ctx
.cct
;
122 ldout(cct
, 10) << "r=" << r
<< dendl
;
124 if (r
== -EBLACKLISTED
) {
125 // allow clean shut down if blacklisted
126 lderr(cct
) << "failed to block writes because client is blacklisted"
129 lderr(cct
) << "failed to block writes: " << cpp_strerror(r
) << dendl
;
130 m_image_ctx
.io_work_queue
->unblock_writes();
139 template <typename I
>
140 void PreReleaseRequest
<I
>::send_wait_for_ops() {
141 CephContext
*cct
= m_image_ctx
.cct
;
142 ldout(cct
, 10) << dendl
;
144 Context
*ctx
= create_context_callback
<
145 PreReleaseRequest
<I
>, &PreReleaseRequest
<I
>::handle_wait_for_ops
>(this);
146 m_async_op_tracker
.wait_for_ops(ctx
);
149 template <typename I
>
150 void PreReleaseRequest
<I
>::handle_wait_for_ops(int r
) {
151 CephContext
*cct
= m_image_ctx
.cct
;
152 ldout(cct
, 10) << dendl
;
154 send_invalidate_cache(false);
157 template <typename I
>
158 void PreReleaseRequest
<I
>::send_invalidate_cache(bool purge_on_error
) {
159 if (m_image_ctx
.object_cacher
== nullptr) {
160 send_flush_notifies();
164 CephContext
*cct
= m_image_ctx
.cct
;
165 ldout(cct
, 10) << "purge_on_error=" << purge_on_error
<< dendl
;
167 RWLock::RLocker
owner_lock(m_image_ctx
.owner_lock
);
168 Context
*ctx
= create_async_context_callback(
169 m_image_ctx
, create_context_callback
<
170 PreReleaseRequest
<I
>,
171 &PreReleaseRequest
<I
>::handle_invalidate_cache
>(this));
172 m_image_ctx
.invalidate_cache(purge_on_error
, ctx
);
175 template <typename I
>
176 void PreReleaseRequest
<I
>::handle_invalidate_cache(int r
) {
177 CephContext
*cct
= m_image_ctx
.cct
;
178 ldout(cct
, 10) << "r=" << r
<< dendl
;
180 if (r
== -EBLACKLISTED
) {
181 lderr(cct
) << "failed to invalidate cache because client is blacklisted"
183 if (!m_image_ctx
.is_cache_empty()) {
184 // force purge the cache after after being blacklisted
185 send_invalidate_cache(true);
188 } else if (r
< 0 && r
!= -EBUSY
) {
189 lderr(cct
) << "failed to invalidate cache: " << cpp_strerror(r
)
191 m_image_ctx
.io_work_queue
->unblock_writes();
197 send_flush_notifies();
200 template <typename I
>
201 void PreReleaseRequest
<I
>::send_flush_notifies() {
202 CephContext
*cct
= m_image_ctx
.cct
;
203 ldout(cct
, 10) << dendl
;
205 using klass
= PreReleaseRequest
<I
>;
207 create_context_callback
<klass
, &klass::handle_flush_notifies
>(this);
208 m_image_ctx
.image_watcher
->flush(ctx
);
211 template <typename I
>
212 void PreReleaseRequest
<I
>::handle_flush_notifies(int r
) {
213 CephContext
*cct
= m_image_ctx
.cct
;
214 ldout(cct
, 10) << dendl
;
217 send_close_journal();
220 template <typename I
>
221 void PreReleaseRequest
<I
>::send_close_journal() {
223 RWLock::WLocker
snap_locker(m_image_ctx
.snap_lock
);
224 std::swap(m_journal
, m_image_ctx
.journal
);
227 if (m_journal
== nullptr) {
228 send_close_object_map();
232 CephContext
*cct
= m_image_ctx
.cct
;
233 ldout(cct
, 10) << dendl
;
235 using klass
= PreReleaseRequest
<I
>;
236 Context
*ctx
= create_context_callback
<klass
, &klass::handle_close_journal
>(
238 m_journal
->close(ctx
);
241 template <typename I
>
242 void PreReleaseRequest
<I
>::handle_close_journal(int r
) {
243 CephContext
*cct
= m_image_ctx
.cct
;
244 ldout(cct
, 10) << "r=" << r
<< dendl
;
247 // error implies some journal events were not flushed -- continue
248 lderr(cct
) << "failed to close journal: " << cpp_strerror(r
) << dendl
;
253 send_close_object_map();
256 template <typename I
>
257 void PreReleaseRequest
<I
>::send_close_object_map() {
259 RWLock::WLocker
snap_locker(m_image_ctx
.snap_lock
);
260 std::swap(m_object_map
, m_image_ctx
.object_map
);
263 if (m_object_map
== nullptr) {
268 CephContext
*cct
= m_image_ctx
.cct
;
269 ldout(cct
, 10) << dendl
;
271 using klass
= PreReleaseRequest
<I
>;
272 Context
*ctx
= create_context_callback
<
273 klass
, &klass::handle_close_object_map
>(this);
274 m_object_map
->close(ctx
);
277 template <typename I
>
278 void PreReleaseRequest
<I
>::handle_close_object_map(int r
) {
279 CephContext
*cct
= m_image_ctx
.cct
;
280 ldout(cct
, 10) << "r=" << r
<< dendl
;
282 // object map shouldn't return errors
289 template <typename I
>
290 void PreReleaseRequest
<I
>::send_unlock() {
291 CephContext
*cct
= m_image_ctx
.cct
;
292 ldout(cct
, 10) << dendl
;
297 template <typename I
>
298 void PreReleaseRequest
<I
>::finish() {
299 m_on_finish
->complete(m_error_result
);
303 } // namespace exclusive_lock
304 } // namespace librbd
306 template class librbd::exclusive_lock::PreReleaseRequest
<librbd::ImageCtx
>;