1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "include/compat.h"
5 #include "CloseImageRequest.h"
6 #include "OpenLocalImageRequest.h"
7 #include "common/debug.h"
8 #include "common/errno.h"
9 #include "librbd/ExclusiveLock.h"
10 #include "librbd/ImageCtx.h"
11 #include "librbd/ImageState.h"
12 #include "librbd/Journal.h"
13 #include "librbd/Utils.h"
14 #include "librbd/asio/ContextWQ.h"
15 #include "librbd/exclusive_lock/Policy.h"
16 #include "librbd/journal/Policy.h"
17 #include "librbd/mirror/GetInfoRequest.h"
18 #include <type_traits>
20 #define dout_context g_ceph_context
21 #define dout_subsys ceph_subsys_rbd_mirror
23 #define dout_prefix *_dout << "rbd::mirror::image_replayer::OpenLocalImageRequest: " \
24 << this << " " << __func__ << " "
28 namespace image_replayer
{
30 using librbd::util::create_context_callback
;
35 struct MirrorExclusiveLockPolicy
: public librbd::exclusive_lock::Policy
{
38 MirrorExclusiveLockPolicy(I
*image_ctx
) : image_ctx(image_ctx
) {
41 bool may_auto_request_lock() override
{
45 int lock_requested(bool force
) override
{
48 std::shared_lock owner_locker
{image_ctx
->owner_lock
};
49 std::shared_lock image_locker
{image_ctx
->image_lock
};
50 if (image_ctx
->journal
== nullptr || image_ctx
->journal
->is_tag_owner()) {
56 // if the local image journal has been closed or if it was (force)
57 // promoted allow the lock to be released to another client
58 image_ctx
->exclusive_lock
->release_lock(nullptr);
63 bool accept_blocked_request(
64 librbd::exclusive_lock::OperationRequestType request_type
) override
{
65 switch (request_type
) {
66 case librbd::exclusive_lock::OPERATION_REQUEST_TYPE_TRASH_SNAP_REMOVE
:
67 case librbd::exclusive_lock::OPERATION_REQUEST_TYPE_FORCE_PROMOTION
:
75 struct MirrorJournalPolicy
: public librbd::journal::Policy
{
76 librbd::asio::ContextWQ
*work_queue
;
78 MirrorJournalPolicy(librbd::asio::ContextWQ
*work_queue
)
79 : work_queue(work_queue
) {
82 bool append_disabled() const override
{
83 // avoid recording any events to the local journal
86 bool journal_disabled() const override
{
90 void allocate_tag_on_lock(Context
*on_finish
) override
{
91 // rbd-mirror will manually create tags by copying them from the peer
92 work_queue
->queue(on_finish
, 0);
96 } // anonymous namespace
99 OpenLocalImageRequest
<I
>::OpenLocalImageRequest(
100 librados::IoCtx
&local_io_ctx
,
102 const std::string
&local_image_id
,
103 librbd::asio::ContextWQ
*work_queue
,
105 : m_local_io_ctx(local_io_ctx
), m_local_image_ctx(local_image_ctx
),
106 m_local_image_id(local_image_id
), m_work_queue(work_queue
),
107 m_on_finish(on_finish
) {
110 template <typename I
>
111 void OpenLocalImageRequest
<I
>::send() {
115 template <typename I
>
116 void OpenLocalImageRequest
<I
>::send_open_image() {
119 *m_local_image_ctx
= I::create("", m_local_image_id
, nullptr,
120 m_local_io_ctx
, false);
122 // ensure non-primary images can be modified
123 (*m_local_image_ctx
)->read_only_mask
=
124 ~librbd::IMAGE_READ_ONLY_FLAG_NON_PRIMARY
;
127 std::scoped_lock locker
{(*m_local_image_ctx
)->owner_lock
,
128 (*m_local_image_ctx
)->image_lock
};
129 (*m_local_image_ctx
)->set_exclusive_lock_policy(
130 new MirrorExclusiveLockPolicy
<I
>(*m_local_image_ctx
));
131 (*m_local_image_ctx
)->set_journal_policy(
132 new MirrorJournalPolicy(m_work_queue
));
135 Context
*ctx
= create_context_callback
<
136 OpenLocalImageRequest
<I
>, &OpenLocalImageRequest
<I
>::handle_open_image
>(
138 (*m_local_image_ctx
)->state
->open(0, ctx
);
141 template <typename I
>
142 void OpenLocalImageRequest
<I
>::handle_open_image(int r
) {
143 dout(20) << ": r=" << r
<< dendl
;
147 dout(10) << ": local image does not exist" << dendl
;
149 derr
<< ": failed to open image '" << m_local_image_id
<< "': "
150 << cpp_strerror(r
) << dendl
;
152 *m_local_image_ctx
= nullptr;
157 send_get_mirror_info();
160 template <typename I
>
161 void OpenLocalImageRequest
<I
>::send_get_mirror_info() {
164 Context
*ctx
= create_context_callback
<
165 OpenLocalImageRequest
<I
>,
166 &OpenLocalImageRequest
<I
>::handle_get_mirror_info
>(
168 auto request
= librbd::mirror::GetInfoRequest
<I
>::create(
169 **m_local_image_ctx
, &m_mirror_image
, &m_promotion_state
,
170 &m_primary_mirror_uuid
, ctx
);
174 template <typename I
>
175 void OpenLocalImageRequest
<I
>::handle_get_mirror_info(int r
) {
176 dout(20) << ": r=" << r
<< dendl
;
179 dout(5) << ": local image is not mirrored" << dendl
;
183 derr
<< ": error querying local image primary status: " << cpp_strerror(r
)
189 if (m_mirror_image
.state
== cls::rbd::MIRROR_IMAGE_STATE_DISABLING
) {
190 dout(5) << ": local image mirroring is being disabled" << dendl
;
191 send_close_image(-ENOENT
);
195 // if the local image owns the tag -- don't steal the lock since
196 // we aren't going to mirror peer data into this image anyway
197 if (m_promotion_state
== librbd::mirror::PROMOTION_STATE_PRIMARY
) {
198 dout(10) << ": local image is primary -- skipping image replay" << dendl
;
199 send_close_image(-EREMOTEIO
);
206 template <typename I
>
207 void OpenLocalImageRequest
<I
>::send_lock_image() {
208 std::shared_lock owner_locker
{(*m_local_image_ctx
)->owner_lock
};
209 if ((*m_local_image_ctx
)->exclusive_lock
== nullptr) {
210 owner_locker
.unlock();
211 if (m_mirror_image
.mode
== cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT
) {
214 derr
<< ": image does not support exclusive lock" << dendl
;
215 send_close_image(-EINVAL
);
222 // disallow any proxied maintenance operations before grabbing lock
223 (*m_local_image_ctx
)->exclusive_lock
->block_requests(-EROFS
);
225 Context
*ctx
= create_context_callback
<
226 OpenLocalImageRequest
<I
>, &OpenLocalImageRequest
<I
>::handle_lock_image
>(
229 (*m_local_image_ctx
)->exclusive_lock
->acquire_lock(ctx
);
232 template <typename I
>
233 void OpenLocalImageRequest
<I
>::handle_lock_image(int r
) {
234 dout(20) << ": r=" << r
<< dendl
;
237 derr
<< ": failed to lock image '" << m_local_image_id
<< "': "
238 << cpp_strerror(r
) << dendl
;
244 std::shared_lock owner_locker
{(*m_local_image_ctx
)->owner_lock
};
245 if ((*m_local_image_ctx
)->exclusive_lock
== nullptr ||
246 !(*m_local_image_ctx
)->exclusive_lock
->is_lock_owner()) {
247 derr
<< ": image is not locked" << dendl
;
248 send_close_image(-EBUSY
);
256 template <typename I
>
257 void OpenLocalImageRequest
<I
>::send_close_image(int r
) {
260 if (m_ret_val
== 0 && r
< 0) {
264 Context
*ctx
= create_context_callback
<
265 OpenLocalImageRequest
<I
>, &OpenLocalImageRequest
<I
>::handle_close_image
>(
267 CloseImageRequest
<I
> *request
= CloseImageRequest
<I
>::create(
268 m_local_image_ctx
, ctx
);
272 template <typename I
>
273 void OpenLocalImageRequest
<I
>::handle_close_image(int r
) {
280 template <typename I
>
281 void OpenLocalImageRequest
<I
>::finish(int r
) {
282 dout(20) << ": r=" << r
<< dendl
;
284 m_on_finish
->complete(r
);
288 } // namespace image_replayer
289 } // namespace mirror
292 template class rbd::mirror::image_replayer::OpenLocalImageRequest
<librbd::ImageCtx
>;