]>
Commit | Line | Data |
---|---|---|
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- | |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
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> | |
19 | ||
20 | #define dout_context g_ceph_context | |
21 | #define dout_subsys ceph_subsys_rbd_mirror | |
22 | #undef dout_prefix | |
23 | #define dout_prefix *_dout << "rbd::mirror::image_replayer::OpenLocalImageRequest: " \ | |
24 | << this << " " << __func__ << " " | |
25 | ||
26 | namespace rbd { | |
27 | namespace mirror { | |
28 | namespace image_replayer { | |
29 | ||
30 | using librbd::util::create_context_callback; | |
31 | ||
32 | namespace { | |
33 | ||
34 | template <typename I> | |
35 | struct MirrorExclusiveLockPolicy : public librbd::exclusive_lock::Policy { | |
36 | I *image_ctx; | |
37 | ||
38 | MirrorExclusiveLockPolicy(I *image_ctx) : image_ctx(image_ctx) { | |
39 | } | |
40 | ||
41 | bool may_auto_request_lock() override { | |
42 | return false; | |
43 | } | |
44 | ||
45 | int lock_requested(bool force) override { | |
46 | int r = -EROFS; | |
47 | { | |
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()) { | |
51 | r = 0; | |
52 | } | |
53 | } | |
54 | ||
55 | if (r == 0) { | |
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); | |
59 | } | |
60 | return r; | |
61 | } | |
62 | ||
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: | |
68 | return true; | |
69 | default: | |
70 | return false; | |
71 | } | |
72 | } | |
73 | }; | |
74 | ||
75 | struct MirrorJournalPolicy : public librbd::journal::Policy { | |
76 | librbd::asio::ContextWQ *work_queue; | |
77 | ||
78 | MirrorJournalPolicy(librbd::asio::ContextWQ *work_queue) | |
79 | : work_queue(work_queue) { | |
80 | } | |
81 | ||
82 | bool append_disabled() const override { | |
83 | // avoid recording any events to the local journal | |
84 | return true; | |
85 | } | |
86 | bool journal_disabled() const override { | |
87 | return false; | |
88 | } | |
89 | ||
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); | |
93 | } | |
94 | }; | |
95 | ||
96 | } // anonymous namespace | |
97 | ||
98 | template <typename I> | |
99 | OpenLocalImageRequest<I>::OpenLocalImageRequest( | |
100 | librados::IoCtx &local_io_ctx, | |
101 | I **local_image_ctx, | |
102 | const std::string &local_image_id, | |
103 | librbd::asio::ContextWQ *work_queue, | |
104 | Context *on_finish) | |
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) { | |
108 | } | |
109 | ||
110 | template <typename I> | |
111 | void OpenLocalImageRequest<I>::send() { | |
112 | send_open_image(); | |
113 | } | |
114 | ||
115 | template <typename I> | |
116 | void OpenLocalImageRequest<I>::send_open_image() { | |
117 | dout(20) << dendl; | |
118 | ||
119 | *m_local_image_ctx = I::create("", m_local_image_id, nullptr, | |
120 | m_local_io_ctx, false); | |
121 | ||
122 | // ensure non-primary images can be modified | |
123 | (*m_local_image_ctx)->read_only_mask = | |
124 | ~librbd::IMAGE_READ_ONLY_FLAG_NON_PRIMARY; | |
125 | ||
126 | { | |
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)); | |
133 | } | |
134 | ||
135 | Context *ctx = create_context_callback< | |
136 | OpenLocalImageRequest<I>, &OpenLocalImageRequest<I>::handle_open_image>( | |
137 | this); | |
138 | (*m_local_image_ctx)->state->open(0, ctx); | |
139 | } | |
140 | ||
141 | template <typename I> | |
142 | void OpenLocalImageRequest<I>::handle_open_image(int r) { | |
143 | dout(20) << ": r=" << r << dendl; | |
144 | ||
145 | if (r < 0) { | |
146 | if (r == -ENOENT) { | |
147 | dout(10) << ": local image does not exist" << dendl; | |
148 | } else { | |
149 | derr << ": failed to open image '" << m_local_image_id << "': " | |
150 | << cpp_strerror(r) << dendl; | |
151 | } | |
152 | *m_local_image_ctx = nullptr; | |
153 | finish(r); | |
154 | return; | |
155 | } | |
156 | ||
157 | send_get_mirror_info(); | |
158 | } | |
159 | ||
160 | template <typename I> | |
161 | void OpenLocalImageRequest<I>::send_get_mirror_info() { | |
162 | dout(20) << dendl; | |
163 | ||
164 | Context *ctx = create_context_callback< | |
165 | OpenLocalImageRequest<I>, | |
166 | &OpenLocalImageRequest<I>::handle_get_mirror_info>( | |
167 | this); | |
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); | |
171 | request->send(); | |
172 | } | |
173 | ||
174 | template <typename I> | |
175 | void OpenLocalImageRequest<I>::handle_get_mirror_info(int r) { | |
176 | dout(20) << ": r=" << r << dendl; | |
177 | ||
178 | if (r == -ENOENT) { | |
179 | dout(5) << ": local image is not mirrored" << dendl; | |
180 | send_close_image(r); | |
181 | return; | |
182 | } else if (r < 0) { | |
183 | derr << ": error querying local image primary status: " << cpp_strerror(r) | |
184 | << dendl; | |
185 | send_close_image(r); | |
186 | return; | |
187 | } | |
188 | ||
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); | |
192 | return; | |
193 | } | |
194 | ||
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); | |
200 | return; | |
201 | } | |
202 | ||
203 | send_lock_image(); | |
204 | } | |
205 | ||
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) { | |
212 | finish(0); | |
213 | } else { | |
214 | derr << ": image does not support exclusive lock" << dendl; | |
215 | send_close_image(-EINVAL); | |
216 | } | |
217 | return; | |
218 | } | |
219 | ||
220 | dout(20) << dendl; | |
221 | ||
222 | // disallow any proxied maintenance operations before grabbing lock | |
223 | (*m_local_image_ctx)->exclusive_lock->block_requests(-EROFS); | |
224 | ||
225 | Context *ctx = create_context_callback< | |
226 | OpenLocalImageRequest<I>, &OpenLocalImageRequest<I>::handle_lock_image>( | |
227 | this); | |
228 | ||
229 | (*m_local_image_ctx)->exclusive_lock->acquire_lock(ctx); | |
230 | } | |
231 | ||
232 | template <typename I> | |
233 | void OpenLocalImageRequest<I>::handle_lock_image(int r) { | |
234 | dout(20) << ": r=" << r << dendl; | |
235 | ||
236 | if (r < 0) { | |
237 | derr << ": failed to lock image '" << m_local_image_id << "': " | |
238 | << cpp_strerror(r) << dendl; | |
239 | send_close_image(r); | |
240 | return; | |
241 | } | |
242 | ||
243 | { | |
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); | |
249 | return; | |
250 | } | |
251 | } | |
252 | ||
253 | finish(0); | |
254 | } | |
255 | ||
256 | template <typename I> | |
257 | void OpenLocalImageRequest<I>::send_close_image(int r) { | |
258 | dout(20) << dendl; | |
259 | ||
260 | if (m_ret_val == 0 && r < 0) { | |
261 | m_ret_val = r; | |
262 | } | |
263 | ||
264 | Context *ctx = create_context_callback< | |
265 | OpenLocalImageRequest<I>, &OpenLocalImageRequest<I>::handle_close_image>( | |
266 | this); | |
267 | CloseImageRequest<I> *request = CloseImageRequest<I>::create( | |
268 | m_local_image_ctx, ctx); | |
269 | request->send(); | |
270 | } | |
271 | ||
272 | template <typename I> | |
273 | void OpenLocalImageRequest<I>::handle_close_image(int r) { | |
274 | dout(20) << dendl; | |
275 | ||
276 | ceph_assert(r == 0); | |
277 | finish(m_ret_val); | |
278 | } | |
279 | ||
280 | template <typename I> | |
281 | void OpenLocalImageRequest<I>::finish(int r) { | |
282 | dout(20) << ": r=" << r << dendl; | |
283 | ||
284 | m_on_finish->complete(r); | |
285 | delete this; | |
286 | } | |
287 | ||
288 | } // namespace image_replayer | |
289 | } // namespace mirror | |
290 | } // namespace rbd | |
291 | ||
292 | template class rbd::mirror::image_replayer::OpenLocalImageRequest<librbd::ImageCtx>; |