Skip to content

Commit cacf7ca

Browse files
committed
librbd/migration: don't instantiate NativeFormat, handle it via dispatch
Trying to shoehorn NativeFormat under FormatInterface doesn't really work. It fundamentally doesn't fit in: - Unlike for RawFormat and QCOWFormat, src_image_ctx for NativeFormat is not dummy -- it's an ImageCtx for a real RBD image. Pre-creating it in OpenSourceImageRequest with the expectation that placeholder values would be overridden later forces NativeFormat to reach into ImageCtx guts, duplicating the logic in the constructor. This also necessitates calling snap_set() in a separate step, since snap_id isn't known at the time ImageCtx is created. - Unlike for RawFormat and QCOWFormat, get_image_size() and get_snapshots() implementations for NativeFormat are dummy. - read() and list_snaps() implementations for NativeFormat are inconsistent: read() passes through io::ImageDispatch layer, but list_snaps() doesn't. Both can be passing through, meaning that in essence these are also dummy. All of this is with today's code. Additional complications arise with planned support for migrating from external clusters where src_image_ctx would require more invasive patching to "move" to an IoCtx belonging to an external cluster's CephContext and also with other work. With the above in mind, NativeFormat actually consists of: 1. Code that parses the "type: native" source spec 2. Code that patches ImageCtx, working around the fact that it's pre-created in OpenSourceImageRequest 3. A bunch of dummy implementations for FormatInterface With this change, (1) is wrapped into a static method that also creates ImageCtx after all required parameters are known and (2) and (3) go away entirely. NativeFormat no longer implements FormatInterface and doesn't get instantiated at all. Signed-off-by: Ilya Dryomov <[email protected]>
1 parent 3bbf1f5 commit cacf7ca

File tree

8 files changed

+181
-265
lines changed

8 files changed

+181
-265
lines changed

src/librbd/migration/ImageDispatch.cc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ bool ImageDispatch<I>::read(
4343
auto cct = m_image_ctx->cct;
4444
ldout(cct, 20) << dendl;
4545

46+
// let io::ImageDispatch layer (IMAGE_DISPATCH_LAYER_CORE) handle
47+
// native format
48+
if (!m_format) {
49+
return false;
50+
}
51+
4652
*dispatch_result = io::DISPATCH_RESULT_COMPLETE;
4753
return m_format->read(aio_comp, io_context->get_read_snap(),
4854
std::move(image_extents), std::move(read_result),
@@ -132,6 +138,12 @@ bool ImageDispatch<I>::list_snaps(
132138
auto cct = m_image_ctx->cct;
133139
ldout(cct, 20) << dendl;
134140

141+
// let io::ImageDispatch layer (IMAGE_DISPATCH_LAYER_CORE) handle
142+
// native format
143+
if (!m_format) {
144+
return false;
145+
}
146+
135147
*dispatch_result = io::DISPATCH_RESULT_COMPLETE;
136148

137149
aio_comp->set_request_count(1);

src/librbd/migration/ImageDispatch.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ class ImageDispatch : public io::ImageDispatchInterface {
8686

8787
private:
8888
ImageCtxT* m_image_ctx;
89+
90+
// empty (nullptr) for native format
8991
std::unique_ptr<FormatInterface> m_format;
9092

9193
void fail_io(int r, io::AioCompletion* aio_comp,

src/librbd/migration/NativeFormat.cc

Lines changed: 66 additions & 189 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616

1717
#define dout_subsys ceph_subsys_rbd
1818
#undef dout_prefix
19-
#define dout_prefix *_dout << "librbd::migration::NativeFormat: " << this \
20-
<< " " << __func__ << ": "
19+
#define dout_prefix *_dout << "librbd::migration::NativeFormat: " << __func__ \
20+
<< ": "
2121

2222
namespace librbd {
2323
namespace migration {
@@ -51,45 +51,47 @@ std::string NativeFormat<I>::build_source_spec(
5151
}
5252

5353
template <typename I>
54-
NativeFormat<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) {
54+
bool NativeFormat<I>::is_source_spec(
55+
const json_spirit::mObject& source_spec_object) {
56+
auto it = source_spec_object.find(TYPE_KEY);
57+
return it != source_spec_object.end() &&
58+
it->second.type() == json_spirit::str_type &&
59+
it->second.get_str() == "native";
5860
}
5961

6062
template <typename I>
61-
void NativeFormat<I>::open(Context* on_finish) {
62-
auto cct = m_image_ctx->cct;
63-
ldout(cct, 10) << dendl;
64-
63+
int NativeFormat<I>::create_image_ctx(
64+
librados::IoCtx& dst_io_ctx,
65+
const json_spirit::mObject& source_spec_object,
66+
bool import_only, uint64_t src_snap_id, I** src_image_ctx) {
67+
auto cct = reinterpret_cast<CephContext*>(dst_io_ctx.cct());
6568
int64_t pool_id = -1;
6669
std::string pool_namespace;
6770
std::string image_name;
6871
std::string image_id;
72+
std::string snap_name;
73+
uint64_t snap_id = CEPH_NOSNAP;
6974

70-
if (auto it = m_json_object.find(POOL_NAME_KEY);
71-
it != m_json_object.end()) {
75+
if (auto it = source_spec_object.find(POOL_NAME_KEY);
76+
it != source_spec_object.end()) {
7277
if (it->second.type() == json_spirit::str_type) {
73-
librados::Rados rados(m_image_ctx->md_ctx);
78+
librados::Rados rados(dst_io_ctx);
7479
pool_id = rados.pool_lookup(it->second.get_str().c_str());
7580
if (pool_id < 0) {
7681
lderr(cct) << "failed to lookup pool" << dendl;
77-
on_finish->complete(static_cast<int>(pool_id));
78-
return;
82+
return static_cast<int>(pool_id);
7983
}
8084
} else {
8185
lderr(cct) << "invalid pool name" << dendl;
82-
on_finish->complete(-EINVAL);
83-
return;
86+
return -EINVAL;
8487
}
8588
}
8689

87-
if (auto it = m_json_object.find(POOL_ID_KEY);
88-
it != m_json_object.end()) {
90+
if (auto it = source_spec_object.find(POOL_ID_KEY);
91+
it != source_spec_object.end()) {
8992
if (pool_id != -1) {
9093
lderr(cct) << "cannot specify both pool name and pool id" << dendl;
91-
on_finish->complete(-EINVAL);
92-
return;
94+
return -EINVAL;
9395
}
9496
if (it->second.type() == json_spirit::int_type) {
9597
pool_id = it->second.get_int64();
@@ -101,232 +103,107 @@ void NativeFormat<I>::open(Context* on_finish) {
101103
}
102104
if (pool_id == -1) {
103105
lderr(cct) << "invalid pool id" << dendl;
104-
on_finish->complete(-EINVAL);
105-
return;
106+
return -EINVAL;
106107
}
107108
}
108109

109110
if (pool_id == -1) {
110111
lderr(cct) << "missing pool name or pool id" << dendl;
111-
on_finish->complete(-EINVAL);
112-
return;
112+
return -EINVAL;
113113
}
114114

115-
if (auto it = m_json_object.find(POOL_NAMESPACE_KEY);
116-
it != m_json_object.end()) {
115+
if (auto it = source_spec_object.find(POOL_NAMESPACE_KEY);
116+
it != source_spec_object.end()) {
117117
if (it->second.type() == json_spirit::str_type) {
118118
pool_namespace = it->second.get_str();
119119
} else {
120120
lderr(cct) << "invalid pool namespace" << dendl;
121-
on_finish->complete(-EINVAL);
122-
return;
121+
return -EINVAL;
123122
}
124123
}
125124

126-
if (auto it = m_json_object.find(IMAGE_NAME_KEY);
127-
it != m_json_object.end()) {
125+
if (auto it = source_spec_object.find(IMAGE_NAME_KEY);
126+
it != source_spec_object.end()) {
128127
if (it->second.type() == json_spirit::str_type) {
129128
image_name = it->second.get_str();
130129
} else {
131130
lderr(cct) << "invalid image name" << dendl;
132-
on_finish->complete(-EINVAL);
133-
return;
131+
return -EINVAL;
134132
}
135133
} else {
136134
lderr(cct) << "missing image name" << dendl;
137-
on_finish->complete(-EINVAL);
138-
return;
135+
return -EINVAL;
139136
}
140137

141-
if (auto it = m_json_object.find(IMAGE_ID_KEY);
142-
it != m_json_object.end()) {
138+
if (auto it = source_spec_object.find(IMAGE_ID_KEY);
139+
it != source_spec_object.end()) {
143140
if (it->second.type() == json_spirit::str_type) {
144141
image_id = it->second.get_str();
145142
} else {
146143
lderr(cct) << "invalid image id" << dendl;
147-
on_finish->complete(-EINVAL);
148-
return;
144+
return -EINVAL;
149145
}
150146
}
151147

152-
if (auto it = m_json_object.find(SNAP_NAME_KEY);
153-
it != m_json_object.end()) {
148+
if (auto it = source_spec_object.find(SNAP_NAME_KEY);
149+
it != source_spec_object.end()) {
154150
if (it->second.type() == json_spirit::str_type) {
155-
m_snap_name = it->second.get_str();
151+
snap_name = it->second.get_str();
156152
} else {
157153
lderr(cct) << "invalid snap name" << dendl;
158-
on_finish->complete(-EINVAL);
159-
return;
154+
return -EINVAL;
160155
}
161156
}
162157

163-
if (auto it = m_json_object.find(SNAP_ID_KEY);
164-
it != m_json_object.end()) {
165-
if (!m_snap_name.empty()) {
158+
if (auto it = source_spec_object.find(SNAP_ID_KEY);
159+
it != source_spec_object.end()) {
160+
if (!snap_name.empty()) {
166161
lderr(cct) << "cannot specify both snap name and snap id" << dendl;
167-
on_finish->complete(-EINVAL);
168-
return;
162+
return -EINVAL;
169163
}
170164
if (it->second.type() == json_spirit::int_type) {
171-
m_snap_id = it->second.get_uint64();
165+
snap_id = it->second.get_uint64();
172166
} else if (it->second.type() == json_spirit::str_type) {
173167
try {
174-
m_snap_id = boost::lexical_cast<uint64_t>(it->second.get_str());
168+
snap_id = boost::lexical_cast<uint64_t>(it->second.get_str());
175169
} catch (boost::bad_lexical_cast&) {
176170
}
177171
}
178-
if (m_snap_id == CEPH_NOSNAP) {
172+
if (snap_id == CEPH_NOSNAP) {
179173
lderr(cct) << "invalid snap id" << dendl;
180-
on_finish->complete(-EINVAL);
181-
return;
174+
return -EINVAL;
182175
}
183176
}
184177

185178
// snapshot is required for import to keep source read-only
186-
if (m_import_only && m_snap_name.empty() && m_snap_id == CEPH_NOSNAP) {
179+
if (import_only && snap_name.empty() && snap_id == CEPH_NOSNAP) {
187180
lderr(cct) << "snapshot required for import" << dendl;
188-
on_finish->complete(-EINVAL);
189-
return;
190-
}
191-
192-
// TODO add support for external clusters
193-
librados::IoCtx io_ctx;
194-
int r = util::create_ioctx(m_image_ctx->md_ctx, "source image",
195-
pool_id, pool_namespace, &io_ctx);
196-
if (r < 0) {
197-
on_finish->complete(r);
198-
return;
199-
}
200-
201-
m_image_ctx->md_ctx.dup(io_ctx);
202-
m_image_ctx->data_ctx.dup(io_ctx);
203-
m_image_ctx->name = image_name;
204-
205-
uint64_t flags = 0;
206-
if (image_id.empty() && !m_import_only) {
207-
flags |= OPEN_FLAG_OLD_FORMAT;
208-
} else {
209-
m_image_ctx->id = image_id;
181+
return -EINVAL;
210182
}
211183

212-
if (m_image_ctx->child != nullptr) {
213-
// set rados flags for reading the parent image
214-
if (m_image_ctx->child->config.template get_val<bool>("rbd_balance_parent_reads")) {
215-
m_image_ctx->set_read_flag(librados::OPERATION_BALANCE_READS);
216-
} else if (m_image_ctx->child->config.template get_val<bool>("rbd_localize_parent_reads")) {
217-
m_image_ctx->set_read_flag(librados::OPERATION_LOCALIZE_READS);
218-
}
184+
// import snapshot is used only for destination image HEAD
185+
// otherwise, src_snap_id corresponds to destination image "opened at"
186+
// snap_id
187+
if (src_snap_id != CEPH_NOSNAP) {
188+
snap_id = src_snap_id;
219189
}
220190

221-
// open the source RBD image
222-
on_finish = new LambdaContext([this, on_finish](int r) {
223-
handle_open(r, on_finish); });
224-
m_image_ctx->state->open(flags, on_finish);
225-
}
226-
227-
template <typename I>
228-
void NativeFormat<I>::handle_open(int r, Context* on_finish) {
229-
auto cct = m_image_ctx->cct;
230-
ldout(cct, 10) << "r=" << r << dendl;
231-
191+
// TODO add support for external clusters
192+
librados::IoCtx src_io_ctx;
193+
int r = util::create_ioctx(dst_io_ctx, "source image", pool_id,
194+
pool_namespace, &src_io_ctx);
232195
if (r < 0) {
233-
lderr(cct) << "failed to open image: " << cpp_strerror(r) << dendl;
234-
on_finish->complete(r);
235-
return;
236-
}
237-
238-
if (m_snap_id == CEPH_NOSNAP && m_snap_name.empty()) {
239-
on_finish->complete(0);
240-
return;
241-
}
242-
243-
if (!m_snap_name.empty()) {
244-
std::shared_lock image_locker{m_image_ctx->image_lock};
245-
m_snap_id = m_image_ctx->get_snap_id(cls::rbd::UserSnapshotNamespace{},
246-
m_snap_name);
247-
}
248-
249-
if (m_snap_id == CEPH_NOSNAP) {
250-
lderr(cct) << "failed to locate snapshot " << m_snap_name << dendl;
251-
on_finish = new LambdaContext([on_finish](int) {
252-
on_finish->complete(-ENOENT); });
253-
m_image_ctx->state->close(on_finish);
254-
return;
196+
return r;
255197
}
256198

257-
on_finish = new LambdaContext([this, on_finish](int r) {
258-
handle_snap_set(r, on_finish); });
259-
m_image_ctx->state->snap_set(m_snap_id, on_finish);
260-
}
261-
262-
template <typename I>
263-
void NativeFormat<I>::handle_snap_set(int r, Context* on_finish) {
264-
auto cct = m_image_ctx->cct;
265-
ldout(cct, 10) << "r=" << r << dendl;
266-
267-
if (r < 0) {
268-
lderr(cct) << "failed to set snapshot " << m_snap_id << ": "
269-
<< cpp_strerror(r) << dendl;
270-
on_finish = new LambdaContext([r, on_finish](int) {
271-
on_finish->complete(r); });
272-
m_image_ctx->state->close(on_finish);
273-
return;
199+
if (!snap_name.empty() && snap_id == CEPH_NOSNAP) {
200+
*src_image_ctx = I::create(image_name, image_id, snap_name.c_str(),
201+
src_io_ctx, true);
202+
} else {
203+
*src_image_ctx = I::create(image_name, image_id, snap_id, src_io_ctx,
204+
true);
274205
}
275-
276-
on_finish->complete(0);
277-
}
278-
279-
template <typename I>
280-
void NativeFormat<I>::close(Context* on_finish) {
281-
auto cct = m_image_ctx->cct;
282-
ldout(cct, 10) << dendl;
283-
284-
// the native librbd::image::CloseRequest handles all cleanup
285-
on_finish->complete(0);
286-
}
287-
288-
template <typename I>
289-
void NativeFormat<I>::get_snapshots(SnapInfos* snap_infos, Context* on_finish) {
290-
auto cct = m_image_ctx->cct;
291-
ldout(cct, 10) << dendl;
292-
293-
m_image_ctx->image_lock.lock_shared();
294-
*snap_infos = m_image_ctx->snap_info;
295-
m_image_ctx->image_lock.unlock_shared();
296-
297-
on_finish->complete(0);
298-
}
299-
300-
template <typename I>
301-
void NativeFormat<I>::get_image_size(uint64_t snap_id, uint64_t* size,
302-
Context* on_finish) {
303-
auto cct = m_image_ctx->cct;
304-
ldout(cct, 10) << dendl;
305-
306-
m_image_ctx->image_lock.lock_shared();
307-
*size = m_image_ctx->get_image_size(snap_id);
308-
m_image_ctx->image_lock.unlock_shared();
309-
310-
311-
on_finish->complete(0);
312-
}
313-
314-
template <typename I>
315-
void NativeFormat<I>::list_snaps(io::Extents&& image_extents,
316-
io::SnapIds&& snap_ids, int list_snaps_flags,
317-
io::SnapshotDelta* snapshot_delta,
318-
const ZTracer::Trace &parent_trace,
319-
Context* on_finish) {
320-
auto cct = m_image_ctx->cct;
321-
ldout(cct, 20) << "image_extents=" << image_extents << dendl;
322-
323-
auto aio_comp = io::AioCompletion::create_and_start(
324-
on_finish, util::get_image_ctx(m_image_ctx), io::AIO_TYPE_GENERIC);
325-
auto req = io::ImageDispatchSpec::create_list_snaps(
326-
*m_image_ctx, io::IMAGE_DISPATCH_LAYER_MIGRATION, aio_comp,
327-
std::move(image_extents), io::ImageArea::DATA, std::move(snap_ids),
328-
list_snaps_flags, snapshot_delta, {});
329-
req->send();
206+
return 0;
330207
}
331208

332209
} // namespace migration

0 commit comments

Comments
 (0)