summaryrefslogtreecommitdiffstats
path: root/src/librbd/image/RefreshParentRequest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/librbd/image/RefreshParentRequest.cc')
-rw-r--r--src/librbd/image/RefreshParentRequest.cc244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/librbd/image/RefreshParentRequest.cc b/src/librbd/image/RefreshParentRequest.cc
new file mode 100644
index 000000000..348226c39
--- /dev/null
+++ b/src/librbd/image/RefreshParentRequest.cc
@@ -0,0 +1,244 @@
+// -*- 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 <typename I>
+RefreshParentRequest<I>::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 <typename I>
+bool RefreshParentRequest<I>::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 <typename I>
+bool RefreshParentRequest<I>::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 <typename I>
+bool RefreshParentRequest<I>::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 <typename I>
+bool RefreshParentRequest<I>::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 <typename I>
+void RefreshParentRequest<I>::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 <typename I>
+void RefreshParentRequest<I>::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 <typename I>
+void RefreshParentRequest<I>::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 <typename I>
+void RefreshParentRequest<I>::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<I>,
+ &RefreshParentRequest<I>::handle_open_parent, false>(this));
+ auto req = migration::OpenSourceImageRequest<I>::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<bool>("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<bool>("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<I>,
+ &RefreshParentRequest<I>::handle_open_parent, false>(this));
+ m_parent_image_ctx->state->open(0U, ctx);
+}
+
+template <typename I>
+Context *RefreshParentRequest<I>::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 <typename I>
+void RefreshParentRequest<I>::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<I>,
+ &RefreshParentRequest<I>::handle_close_parent, false>(this));
+ m_parent_image_ctx->state->close(ctx);
+}
+
+template <typename I>
+Context *RefreshParentRequest<I>::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 <typename I>
+void RefreshParentRequest<I>::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<I>,
+ &RefreshParentRequest<I>::handle_reset_existence_cache, false>(this));
+ m_child_image_ctx.io_object_dispatcher->reset_existence_cache(ctx);
+}
+
+template <typename I>
+Context *RefreshParentRequest<I>::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 <typename I>
+void RefreshParentRequest<I>::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<librbd::ImageCtx>;