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 derr
<< ": error querying local image primary status: " << cpp_strerror(r
)
162 // if the local image owns the tag -- don't steal the lock since
163 // we aren't going to mirror peer data into this image anyway
165 dout(10) << ": local image is primary -- skipping image replay" << dendl
;
166 send_close_image(-EREMOTEIO
);
173 template <typename I
>
174 void OpenLocalImageRequest
<I
>::send_lock_image() {
177 RWLock::RLocker
owner_locker((*m_local_image_ctx
)->owner_lock
);
178 if ((*m_local_image_ctx
)->exclusive_lock
== nullptr) {
179 derr
<< ": image does not support exclusive lock" << dendl
;
180 send_close_image(-EINVAL
);
184 // disallow any proxied maintenance operations before grabbing lock
185 (*m_local_image_ctx
)->exclusive_lock
->block_requests(-EROFS
);
187 Context
*ctx
= create_context_callback
<
188 OpenLocalImageRequest
<I
>, &OpenLocalImageRequest
<I
>::handle_lock_image
>(
191 (*m_local_image_ctx
)->exclusive_lock
->acquire_lock(ctx
);
194 template <typename I
>
195 void OpenLocalImageRequest
<I
>::handle_lock_image(int r
) {
196 dout(20) << ": r=" << r
<< dendl
;
199 derr
<< ": failed to lock image '" << m_local_image_id
<< "': "
200 << cpp_strerror(r
) << dendl
;
206 RWLock::RLocker
owner_locker((*m_local_image_ctx
)->owner_lock
);
207 if ((*m_local_image_ctx
)->exclusive_lock
== nullptr ||
208 !(*m_local_image_ctx
)->exclusive_lock
->is_lock_owner()) {
209 derr
<< ": image is not locked" << dendl
;
210 send_close_image(-EBUSY
);
218 template <typename I
>
219 void OpenLocalImageRequest
<I
>::send_close_image(int r
) {
222 if (m_ret_val
== 0 && r
< 0) {
226 Context
*ctx
= create_context_callback
<
227 OpenLocalImageRequest
<I
>, &OpenLocalImageRequest
<I
>::handle_close_image
>(
229 CloseImageRequest
<I
> *request
= CloseImageRequest
<I
>::create(
230 m_local_image_ctx
, ctx
);
234 template <typename I
>
235 void OpenLocalImageRequest
<I
>::handle_close_image(int r
) {
242 template <typename I
>
243 void OpenLocalImageRequest
<I
>::finish(int r
) {
244 dout(20) << ": r=" << r
<< dendl
;
246 m_on_finish
->complete(r
);
250 } // namespace image_replayer
251 } // namespace mirror
254 template class rbd::mirror::image_replayer::OpenLocalImageRequest
<librbd::ImageCtx
>;