// -*- mode:c++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "librbd/migration/RawSnapshot.h" #include "common/dout.h" #include "common/errno.h" #include "librbd/ImageCtx.h" #include "librbd/Utils.h" #include "librbd/io/AioCompletion.h" #include "librbd/io/ReadResult.h" #include "librbd/migration/SourceSpecBuilder.h" #include "librbd/migration/StreamInterface.h" namespace librbd { namespace migration { namespace { const std::string NAME_KEY{"name"}; } // anonymous namespace #define dout_subsys ceph_subsys_rbd #undef dout_prefix #define dout_prefix *_dout << "librbd::migration::RawSnapshot::OpenRequest " \ << this << " " << __func__ << ": " template struct RawSnapshot::OpenRequest { RawSnapshot* raw_snapshot; Context* on_finish; OpenRequest(RawSnapshot* raw_snapshot, Context* on_finish) : raw_snapshot(raw_snapshot), on_finish(on_finish) { } void send() { open_stream(); } void open_stream() { auto cct = raw_snapshot->m_image_ctx->cct; ldout(cct, 10) << dendl; auto ctx = util::create_context_callback< OpenRequest, &OpenRequest::handle_open_stream>(this); raw_snapshot->m_stream->open(ctx); } void handle_open_stream(int r) { auto cct = raw_snapshot->m_image_ctx->cct; ldout(cct, 10) << "r=" << r << dendl; if (r < 0) { lderr(cct) << "failed to open stream: " << cpp_strerror(r) << dendl; finish(r); return; } get_image_size(); } void get_image_size() { auto cct = raw_snapshot->m_image_ctx->cct; ldout(cct, 10) << dendl; auto ctx = util::create_context_callback< OpenRequest, &OpenRequest::handle_get_image_size>(this); raw_snapshot->m_stream->get_size(&raw_snapshot->m_snap_info.size, ctx); } void handle_get_image_size(int r) { auto cct = raw_snapshot->m_image_ctx->cct; ldout(cct, 10) << "r=" << r << ", " << "image_size=" << raw_snapshot->m_snap_info.size << dendl; if (r < 0) { lderr(cct) << "failed to open stream: " << cpp_strerror(r) << dendl; close_stream(r); return; } finish(0); } void close_stream(int r) { auto cct = raw_snapshot->m_image_ctx->cct; ldout(cct, 10) << dendl; auto ctx = new LambdaContext([this, r](int) { handle_close_stream(r); }); raw_snapshot->m_stream->close(ctx); } void handle_close_stream(int r) { auto cct = raw_snapshot->m_image_ctx->cct; ldout(cct, 10) << "r=" << r << dendl; raw_snapshot->m_stream.reset(); finish(r); } void finish(int r) { auto cct = raw_snapshot->m_image_ctx->cct; ldout(cct, 10) << "r=" << r << dendl; on_finish->complete(r); delete this; } }; #undef dout_prefix #define dout_prefix *_dout << "librbd::migration::RawSnapshot: " << this \ << " " << __func__ << ": " template RawSnapshot::RawSnapshot(I* image_ctx, const json_spirit::mObject& json_object, const SourceSpecBuilder* source_spec_builder, uint64_t index) : m_image_ctx(image_ctx), m_json_object(json_object), m_source_spec_builder(source_spec_builder), m_index(index), m_snap_info({}, {}, 0, {}, 0, 0, {}) { auto cct = m_image_ctx->cct; ldout(cct, 10) << dendl; } template void RawSnapshot::open(SnapshotInterface* previous_snapshot, Context* on_finish) { auto cct = m_image_ctx->cct; // special-case for treating the HEAD revision as a snapshot if (m_index != CEPH_NOSNAP) { auto& name_val = m_json_object[NAME_KEY]; if (name_val.type() == json_spirit::str_type) { m_snap_info.name = name_val.get_str(); } else if (name_val.type() == json_spirit::null_type) { uuid_d uuid_gen; uuid_gen.generate_random(); m_snap_info.name = uuid_gen.to_string(); } else { lderr(cct) << "invalid snapshot name" << dendl; on_finish->complete(-EINVAL); return; } } ldout(cct, 10) << "name=" << m_snap_info.name << dendl; int r = m_source_spec_builder->build_stream(m_json_object, &m_stream); if (r < 0) { lderr(cct) << "failed to build migration stream handler" << cpp_strerror(r) << dendl; on_finish->complete(r); return; } auto req = new OpenRequest(this, on_finish); req->send(); } template void RawSnapshot::close(Context* on_finish) { auto cct = m_image_ctx->cct; ldout(cct, 10) << dendl; if (!m_stream) { on_finish->complete(0); return; } m_stream->close(on_finish); } template void RawSnapshot::read(io::AioCompletion* aio_comp, io::Extents&& image_extents, io::ReadResult&& read_result, int op_flags, int read_flags, const ZTracer::Trace &parent_trace) { auto cct = m_image_ctx->cct; ldout(cct, 20) << "image_extents=" << image_extents << dendl; aio_comp->read_result = std::move(read_result); aio_comp->read_result.set_image_extents(image_extents); aio_comp->set_request_count(1); auto ctx = new io::ReadResult::C_ImageReadRequest(aio_comp, 0, image_extents); // raw directly maps the image-extent IO down to a byte IO extent m_stream->read(std::move(image_extents), &ctx->bl, ctx); } template void RawSnapshot::list_snap(io::Extents&& image_extents, int list_snaps_flags, io::SparseExtents* sparse_extents, const ZTracer::Trace &parent_trace, Context* on_finish) { auto cct = m_image_ctx->cct; ldout(cct, 20) << "image_extents=" << image_extents << dendl; // raw does support sparse extents so list the full IO extent as a delta for (auto& [image_offset, image_length] : image_extents) { sparse_extents->insert(image_offset, image_length, {io::SPARSE_EXTENT_STATE_DATA, image_length}); } on_finish->complete(0); } } // namespace migration } // namespace librbd template class librbd::migration::RawSnapshot;