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 // setting the lock as required will automatically cause the IO
113 // queue to re-request the lock if any IO is queued
114 if (m_image_ctx
.clone_copy_on_read
||
115 m_image_ctx
.test_features(RBD_FEATURE_JOURNALING
)) {
116 m_image_ctx
.io_work_queue
->set_require_lock(io::DIRECTION_BOTH
, true);
118 m_image_ctx
.io_work_queue
->set_require_lock(io::DIRECTION_WRITE
, true);
120 m_image_ctx
.io_work_queue
->block_writes(ctx
);
124 template <typename I
>
125 void PreReleaseRequest
<I
>::handle_block_writes(int r
) {
126 CephContext
*cct
= m_image_ctx
.cct
;
127 ldout(cct
, 10) << "r=" << r
<< dendl
;
129 if (r
== -EBLACKLISTED
) {
130 // allow clean shut down if blacklisted
131 lderr(cct
) << "failed to block writes because client is blacklisted"
134 lderr(cct
) << "failed to block writes: " << cpp_strerror(r
) << dendl
;
135 m_image_ctx
.io_work_queue
->unblock_writes();
144 template <typename I
>
145 void PreReleaseRequest
<I
>::send_wait_for_ops() {
146 CephContext
*cct
= m_image_ctx
.cct
;
147 ldout(cct
, 10) << dendl
;
149 Context
*ctx
= create_context_callback
<
150 PreReleaseRequest
<I
>, &PreReleaseRequest
<I
>::handle_wait_for_ops
>(this);
151 m_async_op_tracker
.wait_for_ops(ctx
);
154 template <typename I
>
155 void PreReleaseRequest
<I
>::handle_wait_for_ops(int r
) {
156 CephContext
*cct
= m_image_ctx
.cct
;
157 ldout(cct
, 10) << dendl
;
159 send_invalidate_cache(false);
162 template <typename I
>
163 void PreReleaseRequest
<I
>::send_invalidate_cache(bool purge_on_error
) {
164 if (m_image_ctx
.object_cacher
== nullptr) {
165 send_flush_notifies();
169 CephContext
*cct
= m_image_ctx
.cct
;
170 ldout(cct
, 10) << "purge_on_error=" << purge_on_error
<< dendl
;
172 RWLock::RLocker
owner_lock(m_image_ctx
.owner_lock
);
173 Context
*ctx
= create_async_context_callback(
174 m_image_ctx
, create_context_callback
<
175 PreReleaseRequest
<I
>,
176 &PreReleaseRequest
<I
>::handle_invalidate_cache
>(this));
177 m_image_ctx
.invalidate_cache(purge_on_error
, ctx
);
180 template <typename I
>
181 void PreReleaseRequest
<I
>::handle_invalidate_cache(int r
) {
182 CephContext
*cct
= m_image_ctx
.cct
;
183 ldout(cct
, 10) << "r=" << r
<< dendl
;
185 if (r
== -EBLACKLISTED
) {
186 lderr(cct
) << "failed to invalidate cache because client is blacklisted"
188 if (!m_image_ctx
.is_cache_empty()) {
189 // force purge the cache after after being blacklisted
190 send_invalidate_cache(true);
193 } else if (r
< 0 && r
!= -EBUSY
) {
194 lderr(cct
) << "failed to invalidate cache: " << cpp_strerror(r
)
196 m_image_ctx
.io_work_queue
->unblock_writes();
202 send_flush_notifies();
205 template <typename I
>
206 void PreReleaseRequest
<I
>::send_flush_notifies() {
207 CephContext
*cct
= m_image_ctx
.cct
;
208 ldout(cct
, 10) << dendl
;
210 using klass
= PreReleaseRequest
<I
>;
212 create_context_callback
<klass
, &klass::handle_flush_notifies
>(this);
213 m_image_ctx
.image_watcher
->flush(ctx
);
216 template <typename I
>
217 void PreReleaseRequest
<I
>::handle_flush_notifies(int r
) {
218 CephContext
*cct
= m_image_ctx
.cct
;
219 ldout(cct
, 10) << dendl
;
222 send_close_journal();
225 template <typename I
>
226 void PreReleaseRequest
<I
>::send_close_journal() {
228 RWLock::WLocker
snap_locker(m_image_ctx
.snap_lock
);
229 std::swap(m_journal
, m_image_ctx
.journal
);
232 if (m_journal
== nullptr) {
233 send_close_object_map();
237 CephContext
*cct
= m_image_ctx
.cct
;
238 ldout(cct
, 10) << dendl
;
240 using klass
= PreReleaseRequest
<I
>;
241 Context
*ctx
= create_context_callback
<klass
, &klass::handle_close_journal
>(
243 m_journal
->close(ctx
);
246 template <typename I
>
247 void PreReleaseRequest
<I
>::handle_close_journal(int r
) {
248 CephContext
*cct
= m_image_ctx
.cct
;
249 ldout(cct
, 10) << "r=" << r
<< dendl
;
252 // error implies some journal events were not flushed -- continue
253 lderr(cct
) << "failed to close journal: " << cpp_strerror(r
) << dendl
;
258 send_close_object_map();
261 template <typename I
>
262 void PreReleaseRequest
<I
>::send_close_object_map() {
264 RWLock::WLocker
snap_locker(m_image_ctx
.snap_lock
);
265 std::swap(m_object_map
, m_image_ctx
.object_map
);
268 if (m_object_map
== nullptr) {
273 CephContext
*cct
= m_image_ctx
.cct
;
274 ldout(cct
, 10) << dendl
;
276 using klass
= PreReleaseRequest
<I
>;
277 Context
*ctx
= create_context_callback
<
278 klass
, &klass::handle_close_object_map
>(this);
279 m_object_map
->close(ctx
);
282 template <typename I
>
283 void PreReleaseRequest
<I
>::handle_close_object_map(int r
) {
284 CephContext
*cct
= m_image_ctx
.cct
;
285 ldout(cct
, 10) << "r=" << r
<< dendl
;
287 // object map shouldn't return errors
294 template <typename I
>
295 void PreReleaseRequest
<I
>::send_unlock() {
296 CephContext
*cct
= m_image_ctx
.cct
;
297 ldout(cct
, 10) << dendl
;
302 template <typename I
>
303 void PreReleaseRequest
<I
>::finish() {
304 m_on_finish
->complete(m_error_result
);
308 } // namespace exclusive_lock
309 } // namespace librbd
311 template class librbd::exclusive_lock::PreReleaseRequest
<librbd::ImageCtx
>;