]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "librbd/mirror/EnableRequest.h" | |
5 | #include "common/dout.h" | |
6 | #include "common/errno.h" | |
7 | #include "cls/rbd/cls_rbd_client.h" | |
8 | #include "librbd/ImageState.h" | |
9 | #include "librbd/Journal.h" | |
7c673cae | 10 | #include "librbd/Utils.h" |
9f95a23c TL |
11 | #include "librbd/mirror/ImageStateUpdateRequest.h" |
12 | #include "librbd/mirror/snapshot/CreatePrimaryRequest.h" | |
7c673cae FG |
13 | |
14 | #define dout_subsys ceph_subsys_rbd | |
15 | #undef dout_prefix | |
9f95a23c TL |
16 | #define dout_prefix *_dout << "librbd::mirror::EnableRequest: " \ |
17 | << this << " " << __func__ << ": " | |
7c673cae FG |
18 | |
19 | namespace librbd { | |
20 | namespace mirror { | |
21 | ||
22 | using util::create_context_callback; | |
23 | using util::create_rados_callback; | |
24 | ||
25 | template <typename I> | |
26 | EnableRequest<I>::EnableRequest(librados::IoCtx &io_ctx, | |
27 | const std::string &image_id, | |
9f95a23c TL |
28 | I* image_ctx, |
29 | cls::rbd::MirrorImageMode mode, | |
7c673cae FG |
30 | const std::string &non_primary_global_image_id, |
31 | ContextWQ *op_work_queue, Context *on_finish) | |
9f95a23c TL |
32 | : m_io_ctx(io_ctx), m_image_id(image_id), m_image_ctx(image_ctx), |
33 | m_mode(mode), m_non_primary_global_image_id(non_primary_global_image_id), | |
7c673cae FG |
34 | m_op_work_queue(op_work_queue), m_on_finish(on_finish), |
35 | m_cct(reinterpret_cast<CephContext*>(io_ctx.cct())) { | |
36 | } | |
37 | ||
38 | template <typename I> | |
39 | void EnableRequest<I>::send() { | |
9f95a23c | 40 | get_mirror_image(); |
7c673cae FG |
41 | } |
42 | ||
43 | template <typename I> | |
9f95a23c TL |
44 | void EnableRequest<I>::get_mirror_image() { |
45 | ldout(m_cct, 10) << dendl; | |
7c673cae FG |
46 | |
47 | librados::ObjectReadOperation op; | |
48 | cls_client::mirror_image_get_start(&op, m_image_id); | |
49 | ||
50 | using klass = EnableRequest<I>; | |
51 | librados::AioCompletion *comp = | |
52 | create_rados_callback<klass, &klass::handle_get_mirror_image>(this); | |
53 | m_out_bl.clear(); | |
54 | int r = m_io_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl); | |
11fdf7f2 | 55 | ceph_assert(r == 0); |
7c673cae FG |
56 | comp->release(); |
57 | } | |
58 | ||
59 | template <typename I> | |
9f95a23c TL |
60 | void EnableRequest<I>::handle_get_mirror_image(int r) { |
61 | ldout(m_cct, 10) << "r=" << r << dendl; | |
7c673cae | 62 | |
9f95a23c | 63 | if (r == 0) { |
11fdf7f2 | 64 | auto iter = m_out_bl.cbegin(); |
9f95a23c | 65 | r = cls_client::mirror_image_get_finish(&iter, &m_mirror_image); |
7c673cae FG |
66 | } |
67 | ||
9f95a23c TL |
68 | if (r == 0 && m_mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_CREATING && |
69 | !m_non_primary_global_image_id.empty()) { | |
70 | // special case where rbd-mirror injects a disabled record to record the | |
71 | // local image id prior to creating ther image | |
72 | ldout(m_cct, 10) << "enabling mirroring on in-progress image replication" | |
73 | << dendl; | |
74 | } else if (r == 0) { | |
75 | if (m_mirror_image.mode != m_mode) { | |
76 | lderr(m_cct) << "invalid current image mirror mode" << dendl; | |
77 | r = -EINVAL; | |
78 | } else if (m_mirror_image.state == cls::rbd::MIRROR_IMAGE_STATE_ENABLED) { | |
79 | ldout(m_cct, 10) << "mirroring is already enabled" << dendl; | |
7c673cae FG |
80 | } else { |
81 | lderr(m_cct) << "currently disabling" << dendl; | |
9f95a23c | 82 | r = -EINVAL; |
7c673cae | 83 | } |
9f95a23c TL |
84 | finish(r); |
85 | return; | |
86 | } else if (r != -ENOENT) { | |
87 | lderr(m_cct) << "failed to retrieve mirror image: " << cpp_strerror(r) | |
7c673cae | 88 | << dendl; |
9f95a23c TL |
89 | finish(r); |
90 | return; | |
7c673cae FG |
91 | } |
92 | ||
9f95a23c TL |
93 | r = 0; |
94 | m_mirror_image.mode = m_mode; | |
7c673cae FG |
95 | if (m_non_primary_global_image_id.empty()) { |
96 | uuid_d uuid_gen; | |
97 | uuid_gen.generate_random(); | |
98 | m_mirror_image.global_image_id = uuid_gen.to_string(); | |
99 | } else { | |
100 | m_mirror_image.global_image_id = m_non_primary_global_image_id; | |
101 | } | |
102 | ||
9f95a23c | 103 | get_tag_owner(); |
11fdf7f2 TL |
104 | } |
105 | ||
106 | template <typename I> | |
9f95a23c TL |
107 | void EnableRequest<I>::get_tag_owner() { |
108 | if (m_mirror_image.mode == cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) { | |
109 | create_primary_snapshot(); | |
110 | return; | |
111 | } else if (!m_non_primary_global_image_id.empty()) { | |
112 | image_state_update(); | |
11fdf7f2 TL |
113 | return; |
114 | } | |
9f95a23c TL |
115 | |
116 | ldout(m_cct, 10) << dendl; | |
11fdf7f2 TL |
117 | |
118 | using klass = EnableRequest<I>; | |
119 | Context *ctx = create_context_callback< | |
120 | klass, &klass::handle_get_tag_owner>(this); | |
121 | librbd::Journal<>::is_tag_owner(m_io_ctx, m_image_id, &m_is_primary, | |
122 | m_op_work_queue, ctx); | |
123 | } | |
124 | ||
125 | template <typename I> | |
9f95a23c TL |
126 | void EnableRequest<I>::handle_get_tag_owner(int r) { |
127 | ldout(m_cct, 10) << "r=" << r << dendl; | |
11fdf7f2 | 128 | |
9f95a23c TL |
129 | if (r < 0) { |
130 | lderr(m_cct) << "failed to check tag ownership: " << cpp_strerror(r) | |
11fdf7f2 | 131 | << dendl; |
9f95a23c TL |
132 | finish(r); |
133 | return; | |
11fdf7f2 TL |
134 | } |
135 | ||
136 | if (!m_is_primary) { | |
137 | lderr(m_cct) << "last journal tag not owned by local cluster" << dendl; | |
9f95a23c TL |
138 | finish(-EINVAL); |
139 | return; | |
11fdf7f2 TL |
140 | } |
141 | ||
9f95a23c | 142 | image_state_update(); |
7c673cae FG |
143 | } |
144 | ||
145 | template <typename I> | |
9f95a23c TL |
146 | void EnableRequest<I>::create_primary_snapshot() { |
147 | if (!m_non_primary_global_image_id.empty()) { | |
148 | // special case for rbd-mirror creating a non-primary image | |
149 | enable_non_primary_feature(); | |
150 | return; | |
151 | } | |
7c673cae | 152 | |
9f95a23c | 153 | ldout(m_cct, 10) << dendl; |
7c673cae | 154 | |
9f95a23c TL |
155 | ceph_assert(m_image_ctx != nullptr); |
156 | auto ctx = create_context_callback< | |
157 | EnableRequest<I>, | |
158 | &EnableRequest<I>::handle_create_primary_snapshot>(this); | |
159 | auto req = snapshot::CreatePrimaryRequest<I>::create( | |
160 | m_image_ctx, m_mirror_image.global_image_id, | |
161 | snapshot::CREATE_PRIMARY_FLAG_IGNORE_EMPTY_PEERS, &m_snap_id, ctx); | |
162 | req->send(); | |
7c673cae FG |
163 | } |
164 | ||
165 | template <typename I> | |
9f95a23c TL |
166 | void EnableRequest<I>::handle_create_primary_snapshot(int r) { |
167 | ldout(m_cct, 10) << "r=" << r << dendl; | |
7c673cae | 168 | |
9f95a23c TL |
169 | if (r < 0) { |
170 | lderr(m_cct) << "failed to create initial primary snapshot: " | |
171 | << cpp_strerror(r) << dendl; | |
172 | finish(r); | |
173 | return; | |
174 | } | |
175 | ||
176 | image_state_update(); | |
177 | } | |
178 | ||
179 | template <typename I> | |
180 | void EnableRequest<I>::enable_non_primary_feature() { | |
181 | if (m_mirror_image.mode != cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT) { | |
182 | image_state_update(); | |
183 | return; | |
7c673cae FG |
184 | } |
185 | ||
9f95a23c TL |
186 | ldout(m_cct, 10) << dendl; |
187 | ||
188 | // ensure image is flagged with non-primary feature so that | |
189 | // standard RBD clients cannot write to it. | |
190 | librados::ObjectWriteOperation op; | |
191 | cls_client::set_features(&op, RBD_FEATURE_NON_PRIMARY, | |
192 | RBD_FEATURE_NON_PRIMARY); | |
193 | ||
194 | auto aio_comp = create_rados_callback< | |
195 | EnableRequest<I>, | |
196 | &EnableRequest<I>::handle_enable_non_primary_feature>(this); | |
197 | int r = m_io_ctx.aio_operate(util::header_name(m_image_id), aio_comp, &op); | |
198 | ceph_assert(r == 0); | |
199 | aio_comp->release(); | |
7c673cae FG |
200 | } |
201 | ||
202 | template <typename I> | |
9f95a23c TL |
203 | void EnableRequest<I>::handle_enable_non_primary_feature(int r) { |
204 | ldout(m_cct, 10) << "r=" << r << dendl; | |
7c673cae | 205 | |
9f95a23c TL |
206 | if (r < 0) { |
207 | lderr(m_cct) << "failed to enable non-primary feature: " | |
208 | << cpp_strerror(r) << dendl; | |
209 | finish(r); | |
210 | return; | |
211 | } | |
7c673cae | 212 | |
9f95a23c TL |
213 | image_state_update(); |
214 | } | |
215 | ||
216 | template <typename I> | |
217 | void EnableRequest<I>::image_state_update() { | |
218 | ldout(m_cct, 10) << dendl; | |
219 | ||
220 | auto ctx = create_context_callback< | |
221 | EnableRequest<I>, &EnableRequest<I>::handle_image_state_update>(this); | |
222 | auto req = ImageStateUpdateRequest<I>::create( | |
223 | m_io_ctx, m_image_id, cls::rbd::MIRROR_IMAGE_STATE_ENABLED, | |
224 | m_mirror_image, ctx); | |
225 | req->send(); | |
7c673cae FG |
226 | } |
227 | ||
228 | template <typename I> | |
9f95a23c TL |
229 | void EnableRequest<I>::handle_image_state_update(int r) { |
230 | ldout(m_cct, 10) << "r=" << r << dendl; | |
7c673cae | 231 | |
9f95a23c TL |
232 | if (r < 0) { |
233 | lderr(m_cct) << "failed to enable mirroring: " << cpp_strerror(r) | |
234 | << dendl; | |
7c673cae FG |
235 | } |
236 | ||
9f95a23c TL |
237 | finish(r); |
238 | } | |
239 | ||
240 | template <typename I> | |
241 | void EnableRequest<I>::finish(int r) { | |
242 | ldout(m_cct, 10) << "r=" << r << dendl; | |
243 | ||
244 | m_on_finish->complete(r); | |
245 | delete this; | |
7c673cae FG |
246 | } |
247 | ||
248 | } // namespace mirror | |
249 | } // namespace librbd | |
250 | ||
251 | template class librbd::mirror::EnableRequest<librbd::ImageCtx>; |