]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/mirror/snapshot/CreatePrimaryRequest.cc
13f7894156ed16cc91513668cad470a9c0b384c9
[ceph.git] / ceph / src / librbd / mirror / snapshot / CreatePrimaryRequest.cc
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/snapshot/CreatePrimaryRequest.h"
5 #include "common/dout.h"
6 #include "common/errno.h"
7 #include "cls/rbd/cls_rbd_client.h"
8 #include "librbd/ImageCtx.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/Operations.h"
11 #include "librbd/Utils.h"
12 #include "librbd/mirror/snapshot/UnlinkPeerRequest.h"
13 #include "librbd/mirror/snapshot/Utils.h"
14
15 #define dout_subsys ceph_subsys_rbd
16
17 #undef dout_prefix
18 #define dout_prefix *_dout << "librbd::mirror::snapshot::CreatePrimaryRequest: " \
19 << this << " " << __func__ << ": "
20
21 namespace librbd {
22 namespace mirror {
23 namespace snapshot {
24
25 using librbd::util::create_context_callback;
26 using librbd::util::create_rados_callback;
27
28 template <typename I>
29 CreatePrimaryRequest<I>::CreatePrimaryRequest(
30 I *image_ctx, const std::string& global_image_id,
31 uint64_t clean_since_snap_id, uint64_t snap_create_flags, uint32_t flags,
32 uint64_t *snap_id, Context *on_finish)
33 : m_image_ctx(image_ctx), m_global_image_id(global_image_id),
34 m_clean_since_snap_id(clean_since_snap_id),
35 m_snap_create_flags(snap_create_flags), m_flags(flags), m_snap_id(snap_id),
36 m_on_finish(on_finish) {
37 m_default_ns_ctx.dup(m_image_ctx->md_ctx);
38 m_default_ns_ctx.set_namespace("");
39 }
40
41 template <typename I>
42 void CreatePrimaryRequest<I>::send() {
43 if (!util::can_create_primary_snapshot(
44 m_image_ctx,
45 ((m_flags & CREATE_PRIMARY_FLAG_DEMOTED) != 0),
46 ((m_flags & CREATE_PRIMARY_FLAG_FORCE) != 0), nullptr, nullptr)) {
47 finish(-EINVAL);
48 return;
49 }
50
51 uuid_d uuid_gen;
52 uuid_gen.generate_random();
53 m_snap_name = ".mirror.primary." + m_global_image_id + "." +
54 uuid_gen.to_string();
55
56 get_mirror_peers();
57 }
58
59 template <typename I>
60 void CreatePrimaryRequest<I>::get_mirror_peers() {
61 CephContext *cct = m_image_ctx->cct;
62 ldout(cct, 15) << dendl;
63
64 librados::ObjectReadOperation op;
65 cls_client::mirror_peer_list_start(&op);
66
67 librados::AioCompletion *comp = create_rados_callback<
68 CreatePrimaryRequest<I>,
69 &CreatePrimaryRequest<I>::handle_get_mirror_peers>(this);
70 m_out_bl.clear();
71 int r = m_default_ns_ctx.aio_operate(RBD_MIRRORING, comp, &op, &m_out_bl);
72 ceph_assert(r == 0);
73 comp->release();
74 }
75
76 template <typename I>
77 void CreatePrimaryRequest<I>::handle_get_mirror_peers(int r) {
78 CephContext *cct = m_image_ctx->cct;
79 ldout(cct, 15) << "r=" << r << dendl;
80
81 std::vector<cls::rbd::MirrorPeer> peers;
82 if (r == 0) {
83 auto iter = m_out_bl.cbegin();
84 r = cls_client::mirror_peer_list_finish(&iter, &peers);
85 }
86
87 if (r < 0) {
88 lderr(cct) << "failed to retrieve mirror peers: " << cpp_strerror(r)
89 << dendl;
90 finish(r);
91 return;
92 }
93
94 for (auto &peer : peers) {
95 if (peer.mirror_peer_direction == cls::rbd::MIRROR_PEER_DIRECTION_RX) {
96 continue;
97 }
98 m_mirror_peer_uuids.insert(peer.uuid);
99 }
100
101 if (m_mirror_peer_uuids.empty() &&
102 ((m_flags & CREATE_PRIMARY_FLAG_IGNORE_EMPTY_PEERS) == 0)) {
103 lderr(cct) << "no mirror tx peers configured for the pool" << dendl;
104 finish(-EINVAL);
105 return;
106 }
107
108 create_snapshot();
109 }
110
111 template <typename I>
112 void CreatePrimaryRequest<I>::create_snapshot() {
113 cls::rbd::MirrorSnapshotNamespace ns{
114 ((m_flags & CREATE_PRIMARY_FLAG_DEMOTED) != 0 ?
115 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED :
116 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY),
117 m_mirror_peer_uuids, "", m_clean_since_snap_id};
118
119 CephContext *cct = m_image_ctx->cct;
120 ldout(cct, 15) << "name=" << m_snap_name << ", "
121 << "ns=" << ns << dendl;
122 auto ctx = create_context_callback<
123 CreatePrimaryRequest<I>,
124 &CreatePrimaryRequest<I>::handle_create_snapshot>(this);
125 m_image_ctx->operations->snap_create(ns, m_snap_name, m_snap_create_flags,
126 m_prog_ctx, ctx);
127 }
128
129 template <typename I>
130 void CreatePrimaryRequest<I>::handle_create_snapshot(int r) {
131 CephContext *cct = m_image_ctx->cct;
132 ldout(cct, 15) << "r=" << r << dendl;
133
134 if (r < 0) {
135 lderr(cct) << "failed to create mirror snapshot: " << cpp_strerror(r)
136 << dendl;
137 finish(r);
138 return;
139 }
140
141 refresh_image();
142 }
143
144 template <typename I>
145 void CreatePrimaryRequest<I>::refresh_image() {
146 // if snapshot created via remote RPC, refresh is required to retrieve
147 // the snapshot id
148 if (m_snap_id == nullptr) {
149 unlink_peer();
150 return;
151 }
152
153 CephContext *cct = m_image_ctx->cct;
154 ldout(cct, 15) << dendl;
155
156 auto ctx = create_context_callback<
157 CreatePrimaryRequest<I>,
158 &CreatePrimaryRequest<I>::handle_refresh_image>(this);
159 m_image_ctx->state->refresh(ctx);
160 }
161
162 template <typename I>
163 void CreatePrimaryRequest<I>::handle_refresh_image(int r) {
164 CephContext *cct = m_image_ctx->cct;
165 ldout(cct, 15) << "r=" << r << dendl;
166
167 if (r < 0) {
168 lderr(cct) << "failed to refresh image: " << cpp_strerror(r) << dendl;
169 finish(r);
170 return;
171 }
172
173 {
174 std::shared_lock image_locker{m_image_ctx->image_lock};
175 *m_snap_id = m_image_ctx->get_snap_id(
176 cls::rbd::MirrorSnapshotNamespace{}, m_snap_name);
177 ldout(cct, 15) << "snap_id=" << *m_snap_id << dendl;
178 }
179
180 unlink_peer();
181 }
182
183 template <typename I>
184 void CreatePrimaryRequest<I>::unlink_peer() {
185 uint64_t max_snapshots = m_image_ctx->config.template get_val<uint64_t>(
186 "rbd_mirroring_max_mirroring_snapshots");
187 ceph_assert(max_snapshots >= 3);
188
189 std::string peer_uuid;
190 uint64_t snap_id = CEPH_NOSNAP;
191
192 for (auto &peer : m_mirror_peer_uuids) {
193 std::shared_lock image_locker{m_image_ctx->image_lock};
194 size_t count = 0;
195 uint64_t unlink_snap_id = 0;
196 for (auto &snap_it : m_image_ctx->snap_info) {
197 auto info = boost::get<cls::rbd::MirrorSnapshotNamespace>(
198 &snap_it.second.snap_namespace);
199 if (info == nullptr) {
200 continue;
201 }
202 if (info->state != cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY) {
203 // reset counters -- we count primary snapshots after the last promotion
204 count = 0;
205 unlink_snap_id = 0;
206 continue;
207 }
208 // call UnlinkPeerRequest only if the snapshot is linked with this peer
209 // or if it's not linked with any peer (happens if mirroring is enabled
210 // on a pool with no peers configured or if UnlinkPeerRequest gets
211 // interrupted)
212 if (info->mirror_peer_uuids.size() == 0) {
213 peer_uuid = peer;
214 snap_id = snap_it.first;
215 break;
216 }
217 if (info->mirror_peer_uuids.count(peer) == 0) {
218 continue;
219 }
220 count++;
221 if (count == 3) {
222 unlink_snap_id = snap_it.first;
223 }
224 if (count > max_snapshots) {
225 peer_uuid = peer;
226 snap_id = unlink_snap_id;
227 break;
228 }
229 }
230 if (snap_id != CEPH_NOSNAP) {
231 break;
232 }
233 }
234
235 if (snap_id == CEPH_NOSNAP) {
236 finish(0);
237 return;
238 }
239
240 CephContext *cct = m_image_ctx->cct;
241 ldout(cct, 15) << "peer=" << peer_uuid << ", snap_id=" << snap_id << dendl;
242
243 auto ctx = create_context_callback<
244 CreatePrimaryRequest<I>,
245 &CreatePrimaryRequest<I>::handle_unlink_peer>(this);
246 auto req = UnlinkPeerRequest<I>::create(m_image_ctx, snap_id, peer_uuid, ctx);
247 req->send();
248 }
249
250 template <typename I>
251 void CreatePrimaryRequest<I>::handle_unlink_peer(int r) {
252 CephContext *cct = m_image_ctx->cct;
253 ldout(cct, 15) << "r=" << r << dendl;
254
255 if (r < 0) {
256 lderr(cct) << "failed to unlink peer: " << cpp_strerror(r) << dendl;
257 finish(0); // not fatal
258 return;
259 }
260
261 unlink_peer();
262 }
263
264 template <typename I>
265 void CreatePrimaryRequest<I>::finish(int r) {
266 CephContext *cct = m_image_ctx->cct;
267 ldout(cct, 15) << "r=" << r << dendl;
268
269 m_on_finish->complete(r);
270 delete this;
271 }
272
273 } // namespace snapshot
274 } // namespace mirror
275 } // namespace librbd
276
277 template class librbd::mirror::snapshot::CreatePrimaryRequest<librbd::ImageCtx>;