X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Flibrbd%2Fimage%2FRefreshParentRequest.cc;fp=src%2Fceph%2Fsrc%2Flibrbd%2Fimage%2FRefreshParentRequest.cc;h=3245ff11158bf643939297880ca00d8fcf102366;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/librbd/image/RefreshParentRequest.cc b/src/ceph/src/librbd/image/RefreshParentRequest.cc new file mode 100644 index 0000000..3245ff1 --- /dev/null +++ b/src/ceph/src/librbd/image/RefreshParentRequest.cc @@ -0,0 +1,241 @@ +// -*- 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;