]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/mirror/snapshot/CreatePrimaryRequest.cc
import ceph pacific 16.2.5
[ceph.git] / ceph / src / librbd / mirror / snapshot / CreatePrimaryRequest.cc
CommitLineData
9f95a23c
TL
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
21namespace librbd {
22namespace mirror {
23namespace snapshot {
24
25using librbd::util::create_context_callback;
26using librbd::util::create_rados_callback;
27
28template <typename I>
29CreatePrimaryRequest<I>::CreatePrimaryRequest(
1911f103 30 I *image_ctx, const std::string& global_image_id,
f67539c2
TL
31 uint64_t clean_since_snap_id, uint64_t snap_create_flags, uint32_t flags,
32 uint64_t *snap_id, Context *on_finish)
9f95a23c 33 : m_image_ctx(image_ctx), m_global_image_id(global_image_id),
f67539c2
TL
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) {
9f95a23c
TL
37 m_default_ns_ctx.dup(m_image_ctx->md_ctx);
38 m_default_ns_ctx.set_namespace("");
39}
40
41template <typename I>
42void 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
59template <typename I>
60void CreatePrimaryRequest<I>::get_mirror_peers() {
61 CephContext *cct = m_image_ctx->cct;
f67539c2 62 ldout(cct, 15) << dendl;
9f95a23c
TL
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
76template <typename I>
77void CreatePrimaryRequest<I>::handle_get_mirror_peers(int r) {
78 CephContext *cct = m_image_ctx->cct;
f67539c2 79 ldout(cct, 15) << "r=" << r << dendl;
9f95a23c
TL
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
111template <typename I>
112void 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),
1911f103 117 m_mirror_peer_uuids, "", m_clean_since_snap_id};
9f95a23c
TL
118
119 CephContext *cct = m_image_ctx->cct;
f67539c2 120 ldout(cct, 15) << "name=" << m_snap_name << ", "
9f95a23c
TL
121 << "ns=" << ns << dendl;
122 auto ctx = create_context_callback<
123 CreatePrimaryRequest<I>,
124 &CreatePrimaryRequest<I>::handle_create_snapshot>(this);
f67539c2
TL
125 m_image_ctx->operations->snap_create(ns, m_snap_name, m_snap_create_flags,
126 m_prog_ctx, ctx);
9f95a23c
TL
127}
128
129template <typename I>
130void CreatePrimaryRequest<I>::handle_create_snapshot(int r) {
131 CephContext *cct = m_image_ctx->cct;
f67539c2 132 ldout(cct, 15) << "r=" << r << dendl;
9f95a23c
TL
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
144template <typename I>
145void 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;
f67539c2 154 ldout(cct, 15) << dendl;
9f95a23c
TL
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
162template <typename I>
163void CreatePrimaryRequest<I>::handle_refresh_image(int r) {
164 CephContext *cct = m_image_ctx->cct;
f67539c2 165 ldout(cct, 15) << "r=" << r << dendl;
9f95a23c
TL
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);
f67539c2 177 ldout(cct, 15) << "snap_id=" << *m_snap_id << dendl;
9f95a23c
TL
178 }
179
180 unlink_peer();
181}
182
183template <typename I>
184void 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;
f67539c2 195 uint64_t unlink_snap_id = 0;
9f95a23c
TL
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;
f67539c2 205 unlink_snap_id = 0;
9f95a23c
TL
206 continue;
207 }
b3b6e05e
TL
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 }
9f95a23c 220 count++;
f67539c2
TL
221 if (count == 3) {
222 unlink_snap_id = snap_it.first;
223 }
224 if (count > max_snapshots) {
9f95a23c 225 peer_uuid = peer;
f67539c2 226 snap_id = unlink_snap_id;
9f95a23c
TL
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;
f67539c2 241 ldout(cct, 15) << "peer=" << peer_uuid << ", snap_id=" << snap_id << dendl;
9f95a23c
TL
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
250template <typename I>
251void CreatePrimaryRequest<I>::handle_unlink_peer(int r) {
252 CephContext *cct = m_image_ctx->cct;
f67539c2 253 ldout(cct, 15) << "r=" << r << dendl;
9f95a23c
TL
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
264template <typename I>
265void CreatePrimaryRequest<I>::finish(int r) {
266 CephContext *cct = m_image_ctx->cct;
f67539c2 267 ldout(cct, 15) << "r=" << r << dendl;
9f95a23c
TL
268
269 m_on_finish->complete(r);
270 delete this;
271}
272
273} // namespace snapshot
274} // namespace mirror
275} // namespace librbd
276
277template class librbd::mirror::snapshot::CreatePrimaryRequest<librbd::ImageCtx>;