// -*- 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 "librbd/ImageCtx.h" #include "librbd/ImageState.h" #include "librbd/Utils.h" #include "librbd/asio/ContextWQ.h" #include "librbd/io/ObjectDispatcherInterface.h" #include "librbd/migration/OpenSourceImageRequest.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 ParentImageInfo &parent_md, const MigrationInfo &migration_info, Context *on_finish) : m_child_image_ctx(child_image_ctx), m_parent_md(parent_md), m_migration_info(migration_info), 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 ParentImageInfo &parent_md, const MigrationInfo &migration_info) { ceph_assert(ceph_mutex_is_locked(child_image_ctx.image_lock)); return (is_open_required(child_image_ctx, parent_md, migration_info) || is_close_required(child_image_ctx, parent_md, migration_info)); } template bool RefreshParentRequest::is_close_required( I &child_image_ctx, const ParentImageInfo &parent_md, const MigrationInfo &migration_info) { return (child_image_ctx.parent != nullptr && !does_parent_exist(child_image_ctx, parent_md, migration_info)); } template bool RefreshParentRequest::is_open_required( I &child_image_ctx, const ParentImageInfo &parent_md, const MigrationInfo &migration_info) { return (does_parent_exist(child_image_ctx, parent_md, migration_info) && (child_image_ctx.parent == nullptr || child_image_ctx.parent->md_ctx.get_id() != parent_md.spec.pool_id || child_image_ctx.parent->md_ctx.get_namespace() != parent_md.spec.pool_namespace || child_image_ctx.parent->id != parent_md.spec.image_id || child_image_ctx.parent->snap_id != parent_md.spec.snap_id)); } template bool RefreshParentRequest::does_parent_exist( I &child_image_ctx, const ParentImageInfo &parent_md, const MigrationInfo &migration_info) { if (child_image_ctx.child != nullptr && child_image_ctx.child->migration_info.empty() && parent_md.overlap == 0) { // intermediate, non-migrating images should only open their parent if they // overlap return false; } return (parent_md.spec.pool_id > -1 && parent_md.overlap > 0) || !migration_info.empty(); } template void RefreshParentRequest::send() { if (is_open_required(m_child_image_ctx, m_parent_md, m_migration_info)) { send_open_parent(); } else { // parent will be closed (if necessary) during finalize send_complete(0); } } template void RefreshParentRequest::apply() { ceph_assert(ceph_mutex_is_wlocked(m_child_image_ctx.image_lock)); 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() { ceph_assert(m_parent_md.spec.pool_id >= 0); CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << dendl; if (!m_migration_info.empty()) { auto ctx = create_async_context_callback( m_child_image_ctx, create_context_callback< RefreshParentRequest, &RefreshParentRequest::handle_open_parent, false>(this)); auto req = migration::OpenSourceImageRequest::create( m_child_image_ctx.md_ctx, &m_child_image_ctx, m_parent_md.spec.snap_id, m_migration_info, &m_parent_image_ctx, ctx); req->send(); return; } librados::IoCtx parent_io_ctx; int r = util::create_ioctx(m_child_image_ctx.md_ctx, "parent image", m_parent_md.spec.pool_id, m_parent_md.spec.pool_namespace, &parent_io_ctx); if (r < 0) { send_complete(r); return; } m_parent_image_ctx = new I("", m_parent_md.spec.image_id, m_parent_md.spec.snap_id, parent_io_ctx, true); m_parent_image_ctx->child = &m_child_image_ctx; // set rados flags for reading the parent image if (m_child_image_ctx.config.template get_val("rbd_balance_parent_reads")) { m_parent_image_ctx->set_read_flag(librados::OPERATION_BALANCE_READS); } else if (m_child_image_ctx.config.template get_val("rbd_localize_parent_reads")) { m_parent_image_ctx->set_read_flag(librados::OPERATION_LOCALIZE_READS); } auto ctx = create_async_context_callback( m_child_image_ctx, create_context_callback< RefreshParentRequest, &RefreshParentRequest::handle_open_parent, false>(this)); m_parent_image_ctx->state->open(0U, ctx); } 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 m_parent_image_ctx = nullptr; } return m_on_finish; } template void RefreshParentRequest::send_close_parent() { ceph_assert(m_parent_image_ctx != nullptr); CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << dendl; auto ctx = create_async_context_callback( m_child_image_ctx, create_context_callback< RefreshParentRequest, &RefreshParentRequest::handle_close_parent, false>(this)); m_parent_image_ctx->state->close(ctx); } template Context *RefreshParentRequest::handle_close_parent(int *result) { CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << " r=" << *result << dendl; m_parent_image_ctx = nullptr; if (*result < 0) { lderr(cct) << "failed to close parent image: " << cpp_strerror(*result) << dendl; } send_reset_existence_cache(); return nullptr; } template void RefreshParentRequest::send_reset_existence_cache() { CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << dendl; Context *ctx = create_async_context_callback( m_child_image_ctx, create_context_callback< RefreshParentRequest, &RefreshParentRequest::handle_reset_existence_cache, false>(this)); m_child_image_ctx.io_object_dispatcher->reset_existence_cache(ctx); } template Context *RefreshParentRequest::handle_reset_existence_cache(int *result) { CephContext *cct = m_child_image_ctx.cct; ldout(cct, 10) << this << " " << __func__ << " r=" << *result << dendl; if (*result < 0) { lderr(cct) << "failed to reset object existence cache: " << cpp_strerror(*result) << dendl; } if (m_error_result < 0) { // propagate errors from opening the image *result = m_error_result; } else { *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;