]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/mirror/snapshot/CreatePrimaryRequest.cc
fd6f9b5023d2a4cdb866f9a520418d628c350695
[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 // refresh is required to retrieve the snapshot id (if snapshot
147 // created via remote RPC) and complete flag (regardless)
148 CephContext *cct = m_image_ctx->cct;
149 ldout(cct, 15) << dendl;
150
151 auto ctx = create_context_callback<
152 CreatePrimaryRequest<I>,
153 &CreatePrimaryRequest<I>::handle_refresh_image>(this);
154 m_image_ctx->state->refresh(ctx);
155 }
156
157 template <typename I>
158 void CreatePrimaryRequest<I>::handle_refresh_image(int r) {
159 CephContext *cct = m_image_ctx->cct;
160 ldout(cct, 15) << "r=" << r << dendl;
161
162 if (r < 0) {
163 lderr(cct) << "failed to refresh image: " << cpp_strerror(r) << dendl;
164 finish(r);
165 return;
166 }
167
168 if (m_snap_id != nullptr) {
169 std::shared_lock image_locker{m_image_ctx->image_lock};
170 *m_snap_id = m_image_ctx->get_snap_id(
171 cls::rbd::MirrorSnapshotNamespace{}, m_snap_name);
172 ldout(cct, 15) << "snap_id=" << *m_snap_id << dendl;
173 }
174
175 unlink_peer();
176 }
177
178 template <typename I>
179 void CreatePrimaryRequest<I>::unlink_peer() {
180 uint64_t max_snapshots = m_image_ctx->config.template get_val<uint64_t>(
181 "rbd_mirroring_max_mirroring_snapshots");
182 ceph_assert(max_snapshots >= 3);
183
184 std::string peer_uuid;
185 uint64_t snap_id = CEPH_NOSNAP;
186
187 for (auto &peer : m_mirror_peer_uuids) {
188 std::shared_lock image_locker{m_image_ctx->image_lock};
189 size_t count = 0;
190 uint64_t unlink_snap_id = 0;
191 for (auto &snap_it : m_image_ctx->snap_info) {
192 auto info = std::get_if<cls::rbd::MirrorSnapshotNamespace>(
193 &snap_it.second.snap_namespace);
194 if (info == nullptr) {
195 continue;
196 }
197 if (info->state != cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY) {
198 // reset counters -- we count primary snapshots after the last promotion
199 count = 0;
200 unlink_snap_id = 0;
201 continue;
202 }
203 // call UnlinkPeerRequest only if the snapshot is linked with this peer
204 // or if it's not linked with any peer (happens if mirroring is enabled
205 // on a pool with no peers configured or if UnlinkPeerRequest gets
206 // interrupted)
207 if (!info->mirror_peer_uuids.empty() &&
208 info->mirror_peer_uuids.count(peer) == 0) {
209 continue;
210 }
211 if (info->mirror_peer_uuids.empty() || !info->complete) {
212 peer_uuid = peer;
213 snap_id = snap_it.first;
214 break;
215 }
216 count++;
217 if (count == max_snapshots) {
218 unlink_snap_id = snap_it.first;
219 }
220 if (count > max_snapshots) {
221 peer_uuid = peer;
222 snap_id = unlink_snap_id;
223 break;
224 }
225 }
226 if (snap_id != CEPH_NOSNAP) {
227 break;
228 }
229 }
230
231 if (snap_id == CEPH_NOSNAP) {
232 finish(0);
233 return;
234 }
235
236 CephContext *cct = m_image_ctx->cct;
237 ldout(cct, 15) << "peer=" << peer_uuid << ", snap_id=" << snap_id << dendl;
238
239 auto ctx = create_context_callback<
240 CreatePrimaryRequest<I>,
241 &CreatePrimaryRequest<I>::handle_unlink_peer>(this);
242 auto req = UnlinkPeerRequest<I>::create(m_image_ctx, snap_id, peer_uuid, true,
243 ctx);
244 req->send();
245 }
246
247 template <typename I>
248 void CreatePrimaryRequest<I>::handle_unlink_peer(int r) {
249 CephContext *cct = m_image_ctx->cct;
250 ldout(cct, 15) << "r=" << r << dendl;
251
252 if (r < 0) {
253 lderr(cct) << "failed to unlink peer: " << cpp_strerror(r) << dendl;
254 finish(0); // not fatal
255 return;
256 }
257
258 unlink_peer();
259 }
260
261 template <typename I>
262 void CreatePrimaryRequest<I>::finish(int r) {
263 CephContext *cct = m_image_ctx->cct;
264 ldout(cct, 15) << "r=" << r << dendl;
265
266 m_on_finish->complete(r);
267 delete this;
268 }
269
270 } // namespace snapshot
271 } // namespace mirror
272 } // namespace librbd
273
274 template class librbd::mirror::snapshot::CreatePrimaryRequest<librbd::ImageCtx>;