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 "IsPrimaryRequest.h"
7 #include "OpenLocalImageRequest.h"
8 #include "common/errno.h"
9 #include "common/WorkQueue.h"
10 #include "librbd/ExclusiveLock.h"
11 #include "librbd/ImageCtx.h"
12 #include "librbd/ImageState.h"
13 #include "librbd/Journal.h"
14 #include "librbd/Utils.h"
15 #include "librbd/exclusive_lock/Policy.h"
16 #include "librbd/journal/Policy.h"
17 #include <type_traits>
19 #define dout_context g_ceph_context
20 #define dout_subsys ceph_subsys_rbd_mirror
22 #define dout_prefix *_dout << "rbd::mirror::image_replayer::OpenLocalImageRequest: " \
23 << this << " " << __func__ << " "
27 namespace image_replayer
{
29 using librbd::util::create_context_callback
;
34 struct MirrorExclusiveLockPolicy
: public librbd::exclusive_lock::Policy
{
37 MirrorExclusiveLockPolicy(I
*image_ctx
) : image_ctx(image_ctx
) {
40 bool may_auto_request_lock() override
{
44 int lock_requested(bool force
) override
{
47 RWLock::RLocker
owner_locker(image_ctx
->owner_lock
);
48 RWLock::RLocker
snap_locker(image_ctx
->snap_lock
);
49 if (image_ctx
->journal
== nullptr || image_ctx
->journal
->is_tag_owner()) {
55 // if the local image journal has been closed or if it was (force)
56 // promoted allow the lock to be released to another client
57 image_ctx
->exclusive_lock
->release_lock(nullptr);
64 struct MirrorJournalPolicy
: public librbd::journal::Policy
{
65 ContextWQ
*work_queue
;
67 MirrorJournalPolicy(ContextWQ
*work_queue
) : work_queue(work_queue
) {
70 bool append_disabled() const override
{
71 // avoid recording any events to the local journal
74 bool journal_disabled() const override
{
78 void allocate_tag_on_lock(Context
*on_finish
) override
{
79 // rbd-mirror will manually create tags by copying them from the peer
80 work_queue
->queue(on_finish
, 0);
84 } // anonymous namespace
87 OpenLocalImageRequest
<I
>::OpenLocalImageRequest(librados::IoCtx
&local_io_ctx
,
89 const std::string
&local_image_id
,
90 ContextWQ
*work_queue
,
92 : m_local_io_ctx(local_io_ctx
), m_local_image_ctx(local_image_ctx
),
93 m_local_image_id(local_image_id
), m_work_queue(work_queue
),
94 m_on_finish(on_finish
) {
98 void OpenLocalImageRequest
<I
>::send() {
102 template <typename I
>
103 void OpenLocalImageRequest
<I
>::send_open_image() {
106 *m_local_image_ctx
= I::create("", m_local_image_id
, nullptr,
107 m_local_io_ctx
, false);
109 RWLock::WLocker
owner_locker((*m_local_image_ctx
)->owner_lock
);
110 RWLock::WLocker
snap_locker((*m_local_image_ctx
)->snap_lock
);
111 (*m_local_image_ctx
)->set_exclusive_lock_policy(
112 new MirrorExclusiveLockPolicy
<I
>(*m_local_image_ctx
));
113 (*m_local_image_ctx
)->set_journal_policy(
114 new MirrorJournalPolicy(m_work_queue
));
117 Context
*ctx
= create_context_callback
<
118 OpenLocalImageRequest
<I
>, &OpenLocalImageRequest
<I
>::handle_open_image
>(
120 (*m_local_image_ctx
)->state
->open(false, ctx
);
123 template <typename I
>
124 void OpenLocalImageRequest
<I
>::handle_open_image(int r
) {
125 dout(20) << ": r=" << r
<< dendl
;
128 derr
<< ": failed to open image '" << m_local_image_id
<< "': "
129 << cpp_strerror(r
) << dendl
;
130 (*m_local_image_ctx
)->destroy();
131 *m_local_image_ctx
= nullptr;
139 template <typename I
>
140 void OpenLocalImageRequest
<I
>::send_is_primary() {
143 Context
*ctx
= create_context_callback
<
144 OpenLocalImageRequest
<I
>, &OpenLocalImageRequest
<I
>::handle_is_primary
>(
146 IsPrimaryRequest
<I
> *request
= IsPrimaryRequest
<I
>::create(*m_local_image_ctx
,
151 template <typename I
>
152 void OpenLocalImageRequest
<I
>::handle_is_primary(int r
) {
153 dout(20) << ": r=" << r
<< dendl
;
156 dout(5) << ": local image is not mirrored" << dendl
;
160 derr
<< ": error querying local image primary status: " << cpp_strerror(r
)
166 // if the local image owns the tag -- don't steal the lock since
167 // we aren't going to mirror peer data into this image anyway
169 dout(10) << ": local image is primary -- skipping image replay" << dendl
;
170 send_close_image(-EREMOTEIO
);
177 template <typename I
>
178 void OpenLocalImageRequest
<I
>::send_lock_image() {
181 RWLock::RLocker
owner_locker((*m_local_image_ctx
)->owner_lock
);
182 if ((*m_local_image_ctx
)->exclusive_lock
== nullptr) {
183 derr
<< ": image does not support exclusive lock" << dendl
;
184 send_close_image(-EINVAL
);
188 // disallow any proxied maintenance operations before grabbing lock
189 (*m_local_image_ctx
)->exclusive_lock
->block_requests(-EROFS
);
191 Context
*ctx
= create_context_callback
<
192 OpenLocalImageRequest
<I
>, &OpenLocalImageRequest
<I
>::handle_lock_image
>(
195 (*m_local_image_ctx
)->exclusive_lock
->acquire_lock(ctx
);
198 template <typename I
>
199 void OpenLocalImageRequest
<I
>::handle_lock_image(int r
) {
200 dout(20) << ": r=" << r
<< dendl
;
203 derr
<< ": failed to lock image '" << m_local_image_id
<< "': "
204 << cpp_strerror(r
) << dendl
;
210 RWLock::RLocker
owner_locker((*m_local_image_ctx
)->owner_lock
);
211 if ((*m_local_image_ctx
)->exclusive_lock
== nullptr ||
212 !(*m_local_image_ctx
)->exclusive_lock
->is_lock_owner()) {
213 derr
<< ": image is not locked" << dendl
;
214 send_close_image(-EBUSY
);
222 template <typename I
>
223 void OpenLocalImageRequest
<I
>::send_close_image(int r
) {
226 if (m_ret_val
== 0 && r
< 0) {
230 Context
*ctx
= create_context_callback
<
231 OpenLocalImageRequest
<I
>, &OpenLocalImageRequest
<I
>::handle_close_image
>(
233 CloseImageRequest
<I
> *request
= CloseImageRequest
<I
>::create(
234 m_local_image_ctx
, ctx
);
238 template <typename I
>
239 void OpenLocalImageRequest
<I
>::handle_close_image(int r
) {
246 template <typename I
>
247 void OpenLocalImageRequest
<I
>::finish(int r
) {
248 dout(20) << ": r=" << r
<< dendl
;
250 m_on_finish
->complete(r
);
254 } // namespace image_replayer
255 } // namespace mirror
258 template class rbd::mirror::image_replayer::OpenLocalImageRequest
<librbd::ImageCtx
>;