]> git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/mirror/snapshot/SetImageStateRequest.cc
d0caccdf58aeed902d18f5891bee689cc163c42f
[ceph.git] / ceph / src / librbd / mirror / snapshot / SetImageStateRequest.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/SetImageStateRequest.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/Utils.h"
10 #include "librbd/image/GetMetadataRequest.h"
11 #include "librbd/mirror/snapshot/WriteImageStateRequest.h"
12
13 #include <boost/algorithm/string/predicate.hpp>
14
15 #define dout_subsys ceph_subsys_rbd
16
17 #undef dout_prefix
18 #define dout_prefix *_dout << "librbd::mirror_snapshot::SetImageStateRequest: " \
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 void SetImageStateRequest<I>::send() {
30 get_snap_limit();
31 }
32
33 template <typename I>
34 void SetImageStateRequest<I>::get_snap_limit() {
35 CephContext *cct = m_image_ctx->cct;
36 ldout(cct, 20) << dendl;
37
38 librados::ObjectReadOperation op;
39 cls_client::snapshot_get_limit_start(&op);
40
41 librados::AioCompletion *comp = create_rados_callback<
42 SetImageStateRequest<I>,
43 &SetImageStateRequest<I>::handle_get_snap_limit>(this);
44 m_bl.clear();
45 int r = m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, comp, &op,
46 &m_bl);
47 ceph_assert(r == 0);
48 comp->release();
49 }
50
51 template <typename I>
52 void SetImageStateRequest<I>::handle_get_snap_limit(int r) {
53 CephContext *cct = m_image_ctx->cct;
54 ldout(cct, 20) << "r=" << r << dendl;
55
56 if (r == 0) {
57 auto it = m_bl.cbegin();
58 r = cls_client::snapshot_get_limit_finish(&it, &m_image_state.snap_limit);
59 }
60
61 if (r < 0) {
62 lderr(cct) << "failed to retrieve snapshot limit: " << cpp_strerror(r)
63 << dendl;
64 finish(r);
65 return;
66 }
67
68 ldout(cct, 20) << "snap_limit=" << m_image_state.snap_limit << dendl;
69
70 get_metadata();
71 }
72
73 template <typename I>
74 void SetImageStateRequest<I>::get_metadata() {
75 CephContext *cct = m_image_ctx->cct;
76 ldout(cct, 20) << dendl;
77
78 auto ctx = create_context_callback<
79 SetImageStateRequest<I>,
80 &SetImageStateRequest<I>::handle_get_metadata>(this);
81 auto req = image::GetMetadataRequest<I>::create(
82 m_image_ctx->md_ctx, m_image_ctx->header_oid, true, "", "", 0,
83 &m_image_state.metadata, ctx);
84 req->send();
85 }
86
87 template <typename I>
88 void SetImageStateRequest<I>::handle_get_metadata(int r) {
89 CephContext *cct = m_image_ctx->cct;
90 ldout(cct, 20) << "r=" << r << dendl;
91
92 if (r < 0) {
93 lderr(cct) << "failed to retrieve metadata: " << cpp_strerror(r)
94 << dendl;
95 finish(r);
96 return;
97 }
98
99 {
100 std::shared_lock image_locker{m_image_ctx->image_lock};
101
102 m_image_state.name = m_image_ctx->name;
103 m_image_state.features =
104 m_image_ctx->features & ~RBD_FEATURES_IMPLICIT_ENABLE;
105
106 for (auto &[snap_id, snap_info] : m_image_ctx->snap_info) {
107 auto type = cls::rbd::get_snap_namespace_type(snap_info.snap_namespace);
108 if (type != cls::rbd::SNAPSHOT_NAMESPACE_TYPE_USER) {
109 // only replicate user snapshots -- trash snapshots will be
110 // replicated by an implicit delete if required
111 continue;
112 }
113 m_image_state.snapshots[snap_id] = {snap_info.snap_namespace,
114 snap_info.name,
115 snap_info.protection_status};
116 }
117 }
118
119 write_image_state();
120 }
121
122 template <typename I>
123 void SetImageStateRequest<I>::write_image_state() {
124 CephContext *cct = m_image_ctx->cct;
125 ldout(cct, 20) << dendl;
126
127 auto ctx = create_context_callback<
128 SetImageStateRequest<I>,
129 &SetImageStateRequest<I>::handle_write_image_state>(this);
130
131 auto req = WriteImageStateRequest<I>::create(m_image_ctx, m_snap_id,
132 m_image_state, ctx);
133 req->send();
134 }
135
136 template <typename I>
137 void SetImageStateRequest<I>::handle_write_image_state(int r) {
138 CephContext *cct = m_image_ctx->cct;
139 ldout(cct, 20) << "r=" << r << dendl;
140
141 if (r < 0) {
142 lderr(cct) << "failed to write image state: " << cpp_strerror(r)
143 << dendl;
144 finish(r);
145 return;
146 }
147
148 update_primary_snapshot();
149 }
150
151 template <typename I>
152 void SetImageStateRequest<I>::update_primary_snapshot() {
153 CephContext *cct = m_image_ctx->cct;
154 ldout(cct, 20) << dendl;
155
156 librados::ObjectWriteOperation op;
157 librbd::cls_client::mirror_image_snapshot_set_copy_progress(
158 &op, m_snap_id, true, 0);
159
160 auto aio_comp = create_rados_callback<
161 SetImageStateRequest<I>,
162 &SetImageStateRequest<I>::handle_update_primary_snapshot>(this);
163 int r = m_image_ctx->md_ctx.aio_operate(m_image_ctx->header_oid, aio_comp,
164 &op);
165 ceph_assert(r == 0);
166 aio_comp->release();
167 }
168
169 template <typename I>
170 void SetImageStateRequest<I>::handle_update_primary_snapshot(int r) {
171 CephContext *cct = m_image_ctx->cct;
172 ldout(cct, 20) << "r=" << r << dendl;
173
174 if (r < 0) {
175 lderr(cct) << "failed to update primary snapshot: " << cpp_strerror(r)
176 << dendl;
177 finish(r);
178 return;
179 }
180
181 finish(0);
182 }
183
184 template <typename I>
185 void SetImageStateRequest<I>::finish(int r) {
186 CephContext *cct = m_image_ctx->cct;
187 ldout(cct, 20) << "r=" << r << dendl;
188
189 m_on_finish->complete(r);
190 delete this;
191 }
192
193 } // namespace snapshot
194 } // namespace mirror
195 } // namespace librbd
196
197 template class librbd::mirror::snapshot::SetImageStateRequest<librbd::ImageCtx>;