1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
15 #define dout_subsys ceph_subsys_rbd
18 #define dout_prefix *_dout << "librbd::mirror::snapshot::CreatePrimaryRequest: " \
19 << this << " " << __func__ << ": "
25 using librbd::util::create_context_callback
;
26 using librbd::util::create_rados_callback
;
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("");
42 void CreatePrimaryRequest
<I
>::send() {
43 if (!util::can_create_primary_snapshot(
45 ((m_flags
& CREATE_PRIMARY_FLAG_DEMOTED
) != 0),
46 ((m_flags
& CREATE_PRIMARY_FLAG_FORCE
) != 0), nullptr, nullptr)) {
52 uuid_gen
.generate_random();
53 m_snap_name
= ".mirror.primary." + m_global_image_id
+ "." +
60 void CreatePrimaryRequest
<I
>::get_mirror_peers() {
61 CephContext
*cct
= m_image_ctx
->cct
;
62 ldout(cct
, 15) << dendl
;
64 librados::ObjectReadOperation op
;
65 cls_client::mirror_peer_list_start(&op
);
67 librados::AioCompletion
*comp
= create_rados_callback
<
68 CreatePrimaryRequest
<I
>,
69 &CreatePrimaryRequest
<I
>::handle_get_mirror_peers
>(this);
71 int r
= m_default_ns_ctx
.aio_operate(RBD_MIRRORING
, comp
, &op
, &m_out_bl
);
77 void CreatePrimaryRequest
<I
>::handle_get_mirror_peers(int r
) {
78 CephContext
*cct
= m_image_ctx
->cct
;
79 ldout(cct
, 15) << "r=" << r
<< dendl
;
81 std::vector
<cls::rbd::MirrorPeer
> peers
;
83 auto iter
= m_out_bl
.cbegin();
84 r
= cls_client::mirror_peer_list_finish(&iter
, &peers
);
88 lderr(cct
) << "failed to retrieve mirror peers: " << cpp_strerror(r
)
94 for (auto &peer
: peers
) {
95 if (peer
.mirror_peer_direction
== cls::rbd::MIRROR_PEER_DIRECTION_RX
) {
98 m_mirror_peer_uuids
.insert(peer
.uuid
);
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
;
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
};
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
,
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
;
135 lderr(cct
) << "failed to create mirror snapshot: " << cpp_strerror(r
)
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
;
151 auto ctx
= create_context_callback
<
152 CreatePrimaryRequest
<I
>,
153 &CreatePrimaryRequest
<I
>::handle_refresh_image
>(this);
154 m_image_ctx
->state
->refresh(ctx
);
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
;
163 lderr(cct
) << "failed to refresh image: " << cpp_strerror(r
) << dendl
;
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
;
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);
184 std::string peer_uuid
;
185 uint64_t snap_id
= CEPH_NOSNAP
;
187 for (auto &peer
: m_mirror_peer_uuids
) {
188 std::shared_lock image_locker
{m_image_ctx
->image_lock
};
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) {
197 if (info
->state
!= cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY
) {
198 // reset counters -- we count primary snapshots after the last promotion
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
207 if (!info
->mirror_peer_uuids
.empty() &&
208 info
->mirror_peer_uuids
.count(peer
) == 0) {
211 if (info
->mirror_peer_uuids
.empty() || !info
->complete
) {
213 snap_id
= snap_it
.first
;
217 if (count
== max_snapshots
) {
218 unlink_snap_id
= snap_it
.first
;
220 if (count
> max_snapshots
) {
222 snap_id
= unlink_snap_id
;
226 if (snap_id
!= CEPH_NOSNAP
) {
231 if (snap_id
== CEPH_NOSNAP
) {
236 CephContext
*cct
= m_image_ctx
->cct
;
237 ldout(cct
, 15) << "peer=" << peer_uuid
<< ", snap_id=" << snap_id
<< dendl
;
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,
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
;
253 lderr(cct
) << "failed to unlink peer: " << cpp_strerror(r
) << dendl
;
254 finish(0); // not fatal
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
;
266 m_on_finish
->complete(r
);
270 } // namespace snapshot
271 } // namespace mirror
272 } // namespace librbd
274 template class librbd::mirror::snapshot::CreatePrimaryRequest
<librbd::ImageCtx
>;