// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "librbd/image/RefreshParentRequest.h" #include "include/rados/librados.hpp" #include "common/dout.h" #include "common/errno.h" #include "common/WorkQueue.h" #include "librbd/ImageCtx.h" #include "librbd/Utils.h" #include "librbd/image/CloseRequest.h" #include "librbd/image/OpenRequest.h" #include "librbd/image/SetSnapRequest.h" #define dout_subsys ceph_subsys_rbd #undef dout_prefix #define dout_prefix *_dout << "librbd::image::RefreshParentRequest: " namespace librbd { namespace image { using util::create_async_context_callback; using util::create_context_callback; template RefreshParentRequest::RefreshParentRequest(I &child_image_ctx, const ParentInfo &parent_md, Context *on_finish) : m_child_image_ctx(child_image_ctx), m_parent_md(parent_md), m_on_finish(on_finish), m_parent_image_ctx(nullptr), m_parent_snap_id(CEPH_NOSNAP), m_error_result(0) { } template bool RefreshParentRequest::is_refresh_required(I &child_image_ctx, const ParentInfo &parent_md) { assert(child_image_ctx.snap_lock.is_locked()); assert(child_image_ctx.parent_lock.is_locked()); return (is_open_required(child_image_ctx, parent_md) || is_close_required(child_image_ctx, parent_md)); } template bool RefreshParentRequest::is_close_required(I &child_image_ctx, const ParentInfo &parent_md) { return (child_image_ctx.parent != nullptr && (parent_md.spec.pool_id == -1 || parent_md.overlap == 0)); } template bool RefreshParentRequest::is_open_required(I &child_image_ctx, const ParentInfo &parent_md) { return (parent_md.spec.pool_id > -1 && parent_md.overlap > 0 && (child_image_ctx.parent == nullptr || child_image_ctx.parent->md_ctx.get_id() != parent_md.spec.pool_id || child_image_ctx.parent->id != parent_md.spec.image_id || child_image_ctx.parent->snap_id != parent_md.spec.snap_id)); } template void RefreshParentRequest::send() { if (is_open_required(m_child_image_ctx, m_parent_md)) { send_open_parent(); } else { // parent will be closed (if necessary) during finalize send_complete(0); } } template void RefreshParentRequest::apply() { if (m_child_image_ctx.parent != nullptr) { // closing parent image m_child_image_ctx.clear_nonexistence_cache(); } assert(m_child_image_ctx.snap_lock.is_wlocked()); assert(m_child_image_ctx.parent_lock.is_wlocked()); std::swap(m_child_image_ctx.parent, m_parent_image_ctx); } template void RefreshParentRequest::finalize(Context *on_finish) { CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << dendl; m_on_finish = on_finish; if (m_parent_image_ctx != nullptr) { send_close_parent(); } else { send_complete(0); } } template void RefreshParentRequest::send_open_parent() { assert(m_parent_md.spec.pool_id >= 0); CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << dendl; librados::Rados rados(m_child_image_ctx.md_ctx); librados::IoCtx parent_io_ctx; int r = rados.ioctx_create2(m_parent_md.spec.pool_id, parent_io_ctx); assert(r == 0); // since we don't know the image and snapshot name, set their ids and // reset the snap_name and snap_exists fields after we read the header m_parent_image_ctx = new I("", m_parent_md.spec.image_id, NULL, parent_io_ctx, true); // set rados flags for reading the parent image if (m_child_image_ctx.balance_parent_reads) { m_parent_image_ctx->set_read_flag(librados::OPERATION_BALANCE_READS); } else if (m_child_image_ctx.localize_parent_reads) { m_parent_image_ctx->set_read_flag(librados::OPERATION_LOCALIZE_READS); } using klass = RefreshParentRequest; Context *ctx = create_async_context_callback( m_child_image_ctx, create_context_callback< klass, &klass::handle_open_parent, false>(this)); OpenRequest *req = OpenRequest::create(m_parent_image_ctx, false, ctx); req->send(); } template Context *RefreshParentRequest::handle_open_parent(int *result) { CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << " r=" << *result << dendl; save_result(result); if (*result < 0) { lderr(cct) << "failed to open parent image: " << cpp_strerror(*result) << dendl; // image already closed by open state machine delete m_parent_image_ctx; m_parent_image_ctx = nullptr; return m_on_finish; } send_set_parent_snap(); return nullptr; } template void RefreshParentRequest::send_set_parent_snap() { assert(m_parent_md.spec.snap_id != CEPH_NOSNAP); CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << dendl; cls::rbd::SnapshotNamespace snap_namespace; std::string snap_name; { RWLock::RLocker snap_locker(m_parent_image_ctx->snap_lock); const SnapInfo *info = m_parent_image_ctx->get_snap_info(m_parent_md.spec.snap_id); if (!info) { lderr(cct) << "failed to locate snapshot: Snapshot with this id not found" << dendl; send_complete(-ENOENT); return; } snap_namespace = info->snap_namespace; snap_name = info->name; } using klass = RefreshParentRequest; Context *ctx = create_context_callback< klass, &klass::handle_set_parent_snap, false>(this); SetSnapRequest *req = SetSnapRequest::create( *m_parent_image_ctx, snap_namespace, snap_name, ctx); req->send(); } template Context *RefreshParentRequest::handle_set_parent_snap(int *result) { CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << " r=" << *result << dendl; save_result(result); if (*result < 0) { lderr(cct) << "failed to set parent snapshot: " << cpp_strerror(*result) << dendl; send_close_parent(); return nullptr; } return m_on_finish; } template void RefreshParentRequest::send_close_parent() { assert(m_parent_image_ctx != nullptr); CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << dendl; using klass = RefreshParentRequest; Context *ctx = create_async_context_callback( m_child_image_ctx, create_context_callback< klass, &klass::handle_close_parent, false>(this)); CloseRequest *req = CloseRequest::create(m_parent_image_ctx, ctx); req->send(); } template Context *RefreshParentRequest::handle_close_parent(int *result) { CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << " r=" << *result << dendl; delete m_parent_image_ctx; if (*result < 0) { lderr(cct) << "failed to close parent image: " << cpp_strerror(*result) << dendl; } if (m_error_result < 0) { // propagate errors from opening the image *result = m_error_result; } else { // ignore errors from closing the image *result = 0; } return m_on_finish; } template void RefreshParentRequest::send_complete(int r) { CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << dendl; m_on_finish->complete(r); } } // namespace image } // namespace librbd template class librbd::image::RefreshParentRequest;