]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/migration/NativeFormat.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / librbd / migration / NativeFormat.cc
CommitLineData
f67539c2
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/migration/NativeFormat.h"
5#include "include/neorados/RADOS.hpp"
6#include "common/dout.h"
7#include "common/errno.h"
8#include "librbd/ImageCtx.h"
9#include "librbd/ImageState.h"
10#include "librbd/Utils.h"
11#include "librbd/asio/ContextWQ.h"
12#include "librbd/io/ImageDispatchSpec.h"
13#include "json_spirit/json_spirit.h"
14#include "boost/lexical_cast.hpp"
15#include <sstream>
16
17#define dout_subsys ceph_subsys_rbd
18#undef dout_prefix
19#define dout_prefix *_dout << "librbd::migration::NativeFormat: " << this \
20 << " " << __func__ << ": "
21
22namespace librbd {
23namespace migration {
24
25namespace {
26
27const std::string TYPE_KEY{"type"};
28const std::string POOL_ID_KEY{"pool_id"};
29const std::string POOL_NAME_KEY{"pool_name"};
30const std::string POOL_NAMESPACE_KEY{"pool_namespace"};
31const std::string IMAGE_NAME_KEY{"image_name"};
32const std::string IMAGE_ID_KEY{"image_id"};
33const std::string SNAP_NAME_KEY{"snap_name"};
34const std::string SNAP_ID_KEY{"snap_id"};
35
36} // anonymous namespace
37
38template <typename I>
39std::string NativeFormat<I>::build_source_spec(
40 int64_t pool_id, const std::string& pool_namespace,
41 const std::string& image_name, const std::string& image_id) {
42 json_spirit::mObject source_spec;
43 source_spec[TYPE_KEY] = "native";
44 source_spec[POOL_ID_KEY] = pool_id;
45 source_spec[POOL_NAMESPACE_KEY] = pool_namespace;
46 source_spec[IMAGE_NAME_KEY] = image_name;
47 if (!image_id.empty()) {
48 source_spec[IMAGE_ID_KEY] = image_id;
49 }
50 return json_spirit::write(source_spec);
51}
52
53template <typename I>
54NativeFormat<I>::NativeFormat(
55 I* image_ctx, const json_spirit::mObject& json_object, bool import_only)
56 : m_image_ctx(image_ctx), m_json_object(json_object),
57 m_import_only(import_only) {
58}
59
60template <typename I>
61void NativeFormat<I>::open(Context* on_finish) {
62 auto cct = m_image_ctx->cct;
63 ldout(cct, 10) << dendl;
64
65 auto& pool_name_val = m_json_object[POOL_NAME_KEY];
66 if (pool_name_val.type() == json_spirit::str_type) {
67 librados::Rados rados(m_image_ctx->md_ctx);
68 librados::IoCtx io_ctx;
69 int r = rados.ioctx_create(pool_name_val.get_str().c_str(), io_ctx);
70 if (r < 0 ) {
71 lderr(cct) << "invalid pool name" << dendl;
72 on_finish->complete(r);
73 return;
74 }
75
76 m_pool_id = io_ctx.get_id();
77 } else if (pool_name_val.type() != json_spirit::null_type) {
78 lderr(cct) << "invalid pool name" << dendl;
79 on_finish->complete(-EINVAL);
80 return;
81 }
82
83 auto& pool_id_val = m_json_object[POOL_ID_KEY];
84 if (m_pool_id != -1 && pool_id_val.type() != json_spirit::null_type) {
85 lderr(cct) << "cannot specify both pool name and pool id" << dendl;
86 on_finish->complete(-EINVAL);
87 return;
88 } else if (pool_id_val.type() == json_spirit::int_type) {
89 m_pool_id = pool_id_val.get_int64();
90 } else if (pool_id_val.type() == json_spirit::str_type) {
91 try {
92 m_pool_id = boost::lexical_cast<int64_t>(pool_id_val.get_str());
93 } catch (boost::bad_lexical_cast &) {
94 }
95 }
96
97 if (m_pool_id == -1) {
98 lderr(cct) << "missing or invalid pool id" << dendl;
99 on_finish->complete(-EINVAL);
100 return;
101 }
102
103 auto& pool_namespace_val = m_json_object[POOL_NAMESPACE_KEY];
104 if (pool_namespace_val.type() == json_spirit::str_type) {
105 m_pool_namespace = pool_namespace_val.get_str();
106 } else if (pool_namespace_val.type() != json_spirit::null_type) {
107 lderr(cct) << "invalid pool namespace" << dendl;
108 on_finish->complete(-EINVAL);
109 return;
110 }
111
112 auto& image_name_val = m_json_object[IMAGE_NAME_KEY];
113 if (image_name_val.type() != json_spirit::str_type) {
114 lderr(cct) << "missing or invalid image name" << dendl;
115 on_finish->complete(-EINVAL);
116 return;
117 }
118 m_image_name = image_name_val.get_str();
119
120 auto& image_id_val = m_json_object[IMAGE_ID_KEY];
121 if (image_id_val.type() == json_spirit::str_type) {
122 m_image_id = image_id_val.get_str();
123 } else if (image_id_val.type() != json_spirit::null_type) {
124 lderr(cct) << "invalid image id" << dendl;
125 on_finish->complete(-EINVAL);
126 return;
127 }
128
129 auto& snap_name_val = m_json_object[SNAP_NAME_KEY];
130 if (snap_name_val.type() == json_spirit::str_type) {
131 m_snap_name = snap_name_val.get_str();
132 } else if (snap_name_val.type() != json_spirit::null_type) {
133 lderr(cct) << "invalid snap name" << dendl;
134 on_finish->complete(-EINVAL);
135 return;
136 }
137
138 auto& snap_id_val = m_json_object[SNAP_ID_KEY];
139 if (!m_snap_name.empty() && snap_id_val.type() != json_spirit::null_type) {
140 lderr(cct) << "cannot specify both snap name and snap id" << dendl;
141 on_finish->complete(-EINVAL);
142 return;
143 } else if (snap_id_val.type() == json_spirit::str_type) {
144 try {
145 m_snap_id = boost::lexical_cast<uint64_t>(snap_id_val.get_str());
146 } catch (boost::bad_lexical_cast &) {
147 }
148 } else if (snap_id_val.type() == json_spirit::int_type) {
149 m_snap_id = snap_id_val.get_uint64();
150 }
151
152 if (snap_id_val.type() != json_spirit::null_type &&
153 m_snap_id == CEPH_NOSNAP) {
154 lderr(cct) << "invalid snap id" << dendl;
155 on_finish->complete(-EINVAL);
156 return;
157 }
158
159 // snapshot is required for import to keep source read-only
160 if (m_import_only && m_snap_name.empty() && m_snap_id == CEPH_NOSNAP) {
161 lderr(cct) << "snapshot required for import" << dendl;
162 on_finish->complete(-EINVAL);
163 return;
164 }
165
166 // TODO add support for external clusters
167 librados::IoCtx io_ctx;
168 int r = util::create_ioctx(m_image_ctx->md_ctx, "source image",
169 m_pool_id, m_pool_namespace, &io_ctx);
170 if (r < 0) {
171 on_finish->complete(r);
172 return;
173 }
174
175 m_image_ctx->md_ctx.dup(io_ctx);
176 m_image_ctx->data_ctx.dup(io_ctx);
177 m_image_ctx->name = m_image_name;
178
179 uint64_t flags = 0;
180 if (m_image_id.empty() && !m_import_only) {
181 flags |= OPEN_FLAG_OLD_FORMAT;
182 } else {
183 m_image_ctx->id = m_image_id;
184 }
185
186 if (m_image_ctx->child != nullptr) {
187 // set rados flags for reading the parent image
188 if (m_image_ctx->child->config.template get_val<bool>("rbd_balance_parent_reads")) {
189 m_image_ctx->set_read_flag(librados::OPERATION_BALANCE_READS);
190 } else if (m_image_ctx->child->config.template get_val<bool>("rbd_localize_parent_reads")) {
191 m_image_ctx->set_read_flag(librados::OPERATION_LOCALIZE_READS);
192 }
193 }
194
195 // open the source RBD image
196 on_finish = new LambdaContext([this, on_finish](int r) {
197 handle_open(r, on_finish); });
198 m_image_ctx->state->open(flags, on_finish);
199}
200
201template <typename I>
202void NativeFormat<I>::handle_open(int r, Context* on_finish) {
203 auto cct = m_image_ctx->cct;
204 ldout(cct, 10) << "r=" << r << dendl;
205
206 if (r < 0) {
207 lderr(cct) << "failed to open image: " << cpp_strerror(r) << dendl;
208 on_finish->complete(r);
209 return;
210 }
211
212 if (m_snap_id == CEPH_NOSNAP && m_snap_name.empty()) {
213 on_finish->complete(0);
214 return;
215 }
216
217 if (!m_snap_name.empty()) {
218 std::shared_lock image_locker{m_image_ctx->image_lock};
219 m_snap_id = m_image_ctx->get_snap_id(cls::rbd::UserSnapshotNamespace{},
220 m_snap_name);
221 }
222
223 if (m_snap_id == CEPH_NOSNAP) {
224 lderr(cct) << "failed to locate snapshot " << m_snap_name << dendl;
225 on_finish = new LambdaContext([on_finish](int) {
226 on_finish->complete(-ENOENT); });
227 m_image_ctx->state->close(on_finish);
228 return;
229 }
230
231 on_finish = new LambdaContext([this, on_finish](int r) {
232 handle_snap_set(r, on_finish); });
233 m_image_ctx->state->snap_set(m_snap_id, on_finish);
234}
235
236template <typename I>
237void NativeFormat<I>::handle_snap_set(int r, Context* on_finish) {
238 auto cct = m_image_ctx->cct;
239 ldout(cct, 10) << "r=" << r << dendl;
240
241 if (r < 0) {
242 lderr(cct) << "failed to set snapshot " << m_snap_id << ": "
243 << cpp_strerror(r) << dendl;
244 on_finish = new LambdaContext([r, on_finish](int) {
245 on_finish->complete(r); });
246 m_image_ctx->state->close(on_finish);
247 return;
248 }
249
250 on_finish->complete(0);
251}
252
253template <typename I>
254void NativeFormat<I>::close(Context* on_finish) {
255 auto cct = m_image_ctx->cct;
256 ldout(cct, 10) << dendl;
257
258 // the native librbd::image::CloseRequest handles all cleanup
259 on_finish->complete(0);
260}
261
262template <typename I>
263void NativeFormat<I>::get_snapshots(SnapInfos* snap_infos, Context* on_finish) {
264 auto cct = m_image_ctx->cct;
265 ldout(cct, 10) << dendl;
266
267 m_image_ctx->image_lock.lock_shared();
268 *snap_infos = m_image_ctx->snap_info;
269 m_image_ctx->image_lock.unlock_shared();
270
271 on_finish->complete(0);
272}
273
274template <typename I>
275void NativeFormat<I>::get_image_size(uint64_t snap_id, uint64_t* size,
276 Context* on_finish) {
277 auto cct = m_image_ctx->cct;
278 ldout(cct, 10) << dendl;
279
280 m_image_ctx->image_lock.lock_shared();
281 *size = m_image_ctx->get_image_size(snap_id);
282 m_image_ctx->image_lock.unlock_shared();
283
284
285 on_finish->complete(0);
286}
287
288template <typename I>
289void NativeFormat<I>::list_snaps(io::Extents&& image_extents,
290 io::SnapIds&& snap_ids, int list_snaps_flags,
291 io::SnapshotDelta* snapshot_delta,
292 const ZTracer::Trace &parent_trace,
293 Context* on_finish) {
294 auto cct = m_image_ctx->cct;
295 ldout(cct, 20) << "image_extents=" << image_extents << dendl;
296
297 auto aio_comp = io::AioCompletion::create_and_start(
298 on_finish, util::get_image_ctx(m_image_ctx), io::AIO_TYPE_GENERIC);
299 auto req = io::ImageDispatchSpec::create_list_snaps(
300 *m_image_ctx, io::IMAGE_DISPATCH_LAYER_MIGRATION, aio_comp,
1e59de90
TL
301 std::move(image_extents), io::ImageArea::DATA, std::move(snap_ids),
302 list_snaps_flags, snapshot_delta, {});
f67539c2
TL
303 req->send();
304}
305
306} // namespace migration
307} // namespace librbd
308
309template class librbd::migration::NativeFormat<librbd::ImageCtx>;