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"
15 #include "librbd/io/ObjectDispatcher.h"
17 #define dout_subsys ceph_subsys_rbd
19 #define dout_prefix *_dout << "librbd::exclusive_lock::PreReleaseRequest: " \
20 << this << " " << __func__ << ": "
23 namespace exclusive_lock
{
25 using util::create_async_context_callback
;
26 using util::create_context_callback
;
29 PreReleaseRequest
<I
>* PreReleaseRequest
<I
>::create(
30 I
&image_ctx
, bool shutting_down
, AsyncOpTracker
&async_op_tracker
,
32 return new PreReleaseRequest(image_ctx
, shutting_down
, async_op_tracker
,
37 PreReleaseRequest
<I
>::PreReleaseRequest(I
&image_ctx
, bool shutting_down
,
38 AsyncOpTracker
&async_op_tracker
,
40 : m_image_ctx(image_ctx
), m_shutting_down(shutting_down
),
41 m_async_op_tracker(async_op_tracker
),
42 m_on_finish(create_async_context_callback(image_ctx
, on_finish
)) {
46 PreReleaseRequest
<I
>::~PreReleaseRequest() {
47 if (!m_shutting_down
) {
48 m_image_ctx
.state
->handle_prepare_lock_complete();
53 void PreReleaseRequest
<I
>::send() {
58 void PreReleaseRequest
<I
>::send_prepare_lock() {
59 if (m_shutting_down
) {
60 send_cancel_op_requests();
64 CephContext
*cct
= m_image_ctx
.cct
;
65 ldout(cct
, 10) << dendl
;
67 // release the lock if the image is not busy performing other actions
68 Context
*ctx
= create_context_callback
<
69 PreReleaseRequest
<I
>, &PreReleaseRequest
<I
>::handle_prepare_lock
>(this);
70 m_image_ctx
.state
->prepare_lock(ctx
);
74 void PreReleaseRequest
<I
>::handle_prepare_lock(int r
) {
75 CephContext
*cct
= m_image_ctx
.cct
;
76 ldout(cct
, 10) << "r=" << r
<< dendl
;
78 send_cancel_op_requests();
82 void PreReleaseRequest
<I
>::send_cancel_op_requests() {
83 CephContext
*cct
= m_image_ctx
.cct
;
84 ldout(cct
, 10) << dendl
;
86 using klass
= PreReleaseRequest
<I
>;
87 Context
*ctx
= create_context_callback
<
88 klass
, &klass::handle_cancel_op_requests
>(this);
89 m_image_ctx
.cancel_async_requests(ctx
);
93 void PreReleaseRequest
<I
>::handle_cancel_op_requests(int r
) {
94 CephContext
*cct
= m_image_ctx
.cct
;
95 ldout(cct
, 10) << "r=" << r
<< dendl
;
102 template <typename I
>
103 void PreReleaseRequest
<I
>::send_block_writes() {
104 CephContext
*cct
= m_image_ctx
.cct
;
105 ldout(cct
, 10) << dendl
;
107 using klass
= PreReleaseRequest
<I
>;
108 Context
*ctx
= create_context_callback
<
109 klass
, &klass::handle_block_writes
>(this);
112 std::shared_lock owner_locker
{m_image_ctx
.owner_lock
};
113 // setting the lock as required will automatically cause the IO
114 // queue to re-request the lock if any IO is queued
115 if (m_image_ctx
.clone_copy_on_read
||
116 m_image_ctx
.test_features(RBD_FEATURE_JOURNALING
)) {
117 m_image_ctx
.io_work_queue
->set_require_lock(io::DIRECTION_BOTH
, true);
119 m_image_ctx
.io_work_queue
->set_require_lock(io::DIRECTION_WRITE
, true);
121 m_image_ctx
.io_work_queue
->block_writes(ctx
);
125 template <typename I
>
126 void PreReleaseRequest
<I
>::handle_block_writes(int r
) {
127 CephContext
*cct
= m_image_ctx
.cct
;
128 ldout(cct
, 10) << "r=" << r
<< dendl
;
130 if (r
== -EBLACKLISTED
) {
131 // allow clean shut down if blacklisted
132 lderr(cct
) << "failed to block writes because client is blacklisted"
135 lderr(cct
) << "failed to block writes: " << cpp_strerror(r
) << dendl
;
136 m_image_ctx
.io_work_queue
->unblock_writes();
145 template <typename I
>
146 void PreReleaseRequest
<I
>::send_wait_for_ops() {
147 CephContext
*cct
= m_image_ctx
.cct
;
148 ldout(cct
, 10) << dendl
;
150 Context
*ctx
= create_context_callback
<
151 PreReleaseRequest
<I
>, &PreReleaseRequest
<I
>::handle_wait_for_ops
>(this);
152 m_async_op_tracker
.wait_for_ops(ctx
);
155 template <typename I
>
156 void PreReleaseRequest
<I
>::handle_wait_for_ops(int r
) {
157 CephContext
*cct
= m_image_ctx
.cct
;
158 ldout(cct
, 10) << dendl
;
160 send_invalidate_cache();
163 template <typename I
>
164 void PreReleaseRequest
<I
>::send_invalidate_cache() {
165 CephContext
*cct
= m_image_ctx
.cct
;
166 ldout(cct
, 10) << dendl
;
168 std::shared_lock owner_lock
{m_image_ctx
.owner_lock
};
169 Context
*ctx
= create_context_callback
<
170 PreReleaseRequest
<I
>,
171 &PreReleaseRequest
<I
>::handle_invalidate_cache
>(this);
172 m_image_ctx
.io_object_dispatcher
->invalidate_cache(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
< 0 && r
!= -EBLACKLISTED
&& r
!= -EBUSY
) {
181 lderr(cct
) << "failed to invalidate cache: " << cpp_strerror(r
)
183 m_image_ctx
.io_work_queue
->unblock_writes();
189 send_flush_notifies();
192 template <typename I
>
193 void PreReleaseRequest
<I
>::send_flush_notifies() {
194 CephContext
*cct
= m_image_ctx
.cct
;
195 ldout(cct
, 10) << dendl
;
197 using klass
= PreReleaseRequest
<I
>;
199 create_context_callback
<klass
, &klass::handle_flush_notifies
>(this);
200 m_image_ctx
.image_watcher
->flush(ctx
);
203 template <typename I
>
204 void PreReleaseRequest
<I
>::handle_flush_notifies(int r
) {
205 CephContext
*cct
= m_image_ctx
.cct
;
206 ldout(cct
, 10) << dendl
;
209 send_close_journal();
212 template <typename I
>
213 void PreReleaseRequest
<I
>::send_close_journal() {
215 std::unique_lock image_locker
{m_image_ctx
.image_lock
};
216 std::swap(m_journal
, m_image_ctx
.journal
);
219 if (m_journal
== nullptr) {
220 send_close_object_map();
224 CephContext
*cct
= m_image_ctx
.cct
;
225 ldout(cct
, 10) << dendl
;
227 using klass
= PreReleaseRequest
<I
>;
228 Context
*ctx
= create_context_callback
<klass
, &klass::handle_close_journal
>(
230 m_journal
->close(ctx
);
233 template <typename I
>
234 void PreReleaseRequest
<I
>::handle_close_journal(int r
) {
235 CephContext
*cct
= m_image_ctx
.cct
;
236 ldout(cct
, 10) << "r=" << r
<< dendl
;
239 // error implies some journal events were not flushed -- continue
240 lderr(cct
) << "failed to close journal: " << cpp_strerror(r
) << dendl
;
246 send_close_object_map();
249 template <typename I
>
250 void PreReleaseRequest
<I
>::send_close_object_map() {
252 std::unique_lock image_locker
{m_image_ctx
.image_lock
};
253 std::swap(m_object_map
, m_image_ctx
.object_map
);
256 if (m_object_map
== nullptr) {
261 CephContext
*cct
= m_image_ctx
.cct
;
262 ldout(cct
, 10) << dendl
;
264 using klass
= PreReleaseRequest
<I
>;
265 Context
*ctx
= create_context_callback
<
266 klass
, &klass::handle_close_object_map
>(this, m_object_map
);
267 m_object_map
->close(ctx
);
270 template <typename I
>
271 void PreReleaseRequest
<I
>::handle_close_object_map(int r
) {
272 CephContext
*cct
= m_image_ctx
.cct
;
273 ldout(cct
, 10) << "r=" << r
<< dendl
;
276 lderr(cct
) << "failed to close object map: " << cpp_strerror(r
) << dendl
;
283 template <typename I
>
284 void PreReleaseRequest
<I
>::send_unlock() {
285 CephContext
*cct
= m_image_ctx
.cct
;
286 ldout(cct
, 10) << dendl
;
291 template <typename I
>
292 void PreReleaseRequest
<I
>::finish() {
293 m_on_finish
->complete(m_error_result
);
297 } // namespace exclusive_lock
298 } // namespace librbd
300 template class librbd::exclusive_lock::PreReleaseRequest
<librbd::ImageCtx
>;