summaryrefslogtreecommitdiffstats
path: root/src/librbd/io/ImageDispatcher.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/librbd/io/ImageDispatcher.cc324
1 files changed, 324 insertions, 0 deletions
diff --git a/src/librbd/io/ImageDispatcher.cc b/src/librbd/io/ImageDispatcher.cc
new file mode 100644
index 000000000..4aa7929b2
--- /dev/null
+++ b/src/librbd/io/ImageDispatcher.cc
@@ -0,0 +1,324 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/io/ImageDispatcher.h"
+#include "include/Context.h"
+#include "common/AsyncOpTracker.h"
+#include "common/dout.h"
+#include "librbd/ImageCtx.h"
+#include "librbd/crypto/CryptoImageDispatch.h"
+#include "librbd/io/ImageDispatch.h"
+#include "librbd/io/ImageDispatchInterface.h"
+#include "librbd/io/ImageDispatchSpec.h"
+#include "librbd/io/QueueImageDispatch.h"
+#include "librbd/io/QosImageDispatch.h"
+#include "librbd/io/RefreshImageDispatch.h"
+#include "librbd/io/Utils.h"
+#include "librbd/io/WriteBlockImageDispatch.h"
+#include <boost/variant.hpp>
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::io::ImageDispatcher: " << this \
+ << " " << __func__ << ": "
+
+namespace librbd {
+namespace io {
+
+template <typename I>
+struct ImageDispatcher<I>::SendVisitor : public boost::static_visitor<bool> {
+ ImageDispatchInterface* image_dispatch;
+ ImageDispatchSpec* image_dispatch_spec;
+
+ SendVisitor(ImageDispatchInterface* image_dispatch,
+ ImageDispatchSpec* image_dispatch_spec)
+ : image_dispatch(image_dispatch),
+ image_dispatch_spec(image_dispatch_spec) {
+ }
+
+ bool operator()(ImageDispatchSpec::Read& read) const {
+ return image_dispatch->read(
+ image_dispatch_spec->aio_comp,
+ std::move(image_dispatch_spec->image_extents),
+ std::move(read.read_result), image_dispatch_spec->io_context,
+ image_dispatch_spec->op_flags, read.read_flags,
+ image_dispatch_spec->parent_trace, image_dispatch_spec->tid,
+ &image_dispatch_spec->image_dispatch_flags,
+ &image_dispatch_spec->dispatch_result,
+ &image_dispatch_spec->aio_comp->image_dispatcher_ctx,
+ &image_dispatch_spec->dispatcher_ctx);
+ }
+
+ bool operator()(ImageDispatchSpec::Discard& discard) const {
+ return image_dispatch->discard(
+ image_dispatch_spec->aio_comp,
+ std::move(image_dispatch_spec->image_extents),
+ discard.discard_granularity_bytes, image_dispatch_spec->parent_trace,
+ image_dispatch_spec->tid, &image_dispatch_spec->image_dispatch_flags,
+ &image_dispatch_spec->dispatch_result,
+ &image_dispatch_spec->aio_comp->image_dispatcher_ctx,
+ &image_dispatch_spec->dispatcher_ctx);
+ }
+
+ bool operator()(ImageDispatchSpec::Write& write) const {
+ return image_dispatch->write(
+ image_dispatch_spec->aio_comp,
+ std::move(image_dispatch_spec->image_extents), std::move(write.bl),
+ image_dispatch_spec->op_flags, image_dispatch_spec->parent_trace,
+ image_dispatch_spec->tid, &image_dispatch_spec->image_dispatch_flags,
+ &image_dispatch_spec->dispatch_result,
+ &image_dispatch_spec->aio_comp->image_dispatcher_ctx,
+ &image_dispatch_spec->dispatcher_ctx);
+ }
+
+ bool operator()(ImageDispatchSpec::WriteSame& write_same) const {
+ return image_dispatch->write_same(
+ image_dispatch_spec->aio_comp,
+ std::move(image_dispatch_spec->image_extents), std::move(write_same.bl),
+ image_dispatch_spec->op_flags, image_dispatch_spec->parent_trace,
+ image_dispatch_spec->tid, &image_dispatch_spec->image_dispatch_flags,
+ &image_dispatch_spec->dispatch_result,
+ &image_dispatch_spec->aio_comp->image_dispatcher_ctx,
+ &image_dispatch_spec->dispatcher_ctx);
+ }
+
+ bool operator()(
+ ImageDispatchSpec::CompareAndWrite& compare_and_write) const {
+ return image_dispatch->compare_and_write(
+ image_dispatch_spec->aio_comp,
+ std::move(image_dispatch_spec->image_extents),
+ std::move(compare_and_write.cmp_bl), std::move(compare_and_write.bl),
+ compare_and_write.mismatch_offset,
+ image_dispatch_spec->op_flags, image_dispatch_spec->parent_trace,
+ image_dispatch_spec->tid, &image_dispatch_spec->image_dispatch_flags,
+ &image_dispatch_spec->dispatch_result,
+ &image_dispatch_spec->aio_comp->image_dispatcher_ctx,
+ &image_dispatch_spec->dispatcher_ctx);
+ }
+
+ bool operator()(ImageDispatchSpec::Flush& flush) const {
+ return image_dispatch->flush(
+ image_dispatch_spec->aio_comp, flush.flush_source,
+ image_dispatch_spec->parent_trace, image_dispatch_spec->tid,
+ &image_dispatch_spec->image_dispatch_flags,
+ &image_dispatch_spec->dispatch_result,
+ &image_dispatch_spec->aio_comp->image_dispatcher_ctx,
+ &image_dispatch_spec->dispatcher_ctx);
+ }
+
+ bool operator()(ImageDispatchSpec::ListSnaps& list_snaps) const {
+ return image_dispatch->list_snaps(
+ image_dispatch_spec->aio_comp,
+ std::move(image_dispatch_spec->image_extents),
+ std::move(list_snaps.snap_ids), list_snaps.list_snaps_flags,
+ list_snaps.snapshot_delta, image_dispatch_spec->parent_trace,
+ image_dispatch_spec->tid, &image_dispatch_spec->image_dispatch_flags,
+ &image_dispatch_spec->dispatch_result,
+ &image_dispatch_spec->aio_comp->image_dispatcher_ctx,
+ &image_dispatch_spec->dispatcher_ctx);
+ }
+};
+
+template <typename I>
+struct ImageDispatcher<I>::PreprocessVisitor
+ : public boost::static_visitor<bool> {
+ ImageDispatcher<I>* image_dispatcher;
+ ImageDispatchSpec* image_dispatch_spec;
+
+ PreprocessVisitor(ImageDispatcher<I>* image_dispatcher,
+ ImageDispatchSpec* image_dispatch_spec)
+ : image_dispatcher(image_dispatcher),
+ image_dispatch_spec(image_dispatch_spec) {
+ }
+
+ bool clip_request() const {
+ auto area = (image_dispatch_spec->image_dispatch_flags &
+ IMAGE_DISPATCH_FLAG_CRYPTO_HEADER ? ImageArea::CRYPTO_HEADER :
+ ImageArea::DATA);
+ int r = util::clip_request(image_dispatcher->m_image_ctx,
+ &image_dispatch_spec->image_extents, area);
+ if (r < 0) {
+ image_dispatch_spec->fail(r);
+ return true;
+ }
+ return false;
+ }
+
+ bool operator()(ImageDispatchSpec::Read& read) const {
+ if ((read.read_flags & READ_FLAG_DISABLE_CLIPPING) != 0) {
+ return false;
+ }
+ return clip_request();
+ }
+
+ bool operator()(ImageDispatchSpec::Flush&) const {
+ return clip_request();
+ }
+
+ bool operator()(ImageDispatchSpec::ListSnaps&) const {
+ return false;
+ }
+
+ template <typename T>
+ bool operator()(T&) const {
+ if (clip_request()) {
+ return true;
+ }
+
+ std::shared_lock image_locker{image_dispatcher->m_image_ctx->image_lock};
+ if (image_dispatcher->m_image_ctx->snap_id != CEPH_NOSNAP ||
+ image_dispatcher->m_image_ctx->read_only) {
+ image_dispatch_spec->fail(-EROFS);
+ return true;
+ }
+ return false;
+ }
+};
+
+template <typename I>
+ImageDispatcher<I>::ImageDispatcher(I* image_ctx)
+ : Dispatcher<I, ImageDispatcherInterface>(image_ctx) {
+ // configure the core image dispatch handler on startup
+ auto image_dispatch = new ImageDispatch(image_ctx);
+ this->register_dispatch(image_dispatch);
+
+ auto queue_image_dispatch = new QueueImageDispatch(image_ctx);
+ this->register_dispatch(queue_image_dispatch);
+
+ m_qos_image_dispatch = new QosImageDispatch<I>(image_ctx);
+ this->register_dispatch(m_qos_image_dispatch);
+
+ auto refresh_image_dispatch = new RefreshImageDispatch(image_ctx);
+ this->register_dispatch(refresh_image_dispatch);
+
+ m_write_block_dispatch = new WriteBlockImageDispatch<I>(image_ctx);
+ this->register_dispatch(m_write_block_dispatch);
+}
+
+template <typename I>
+void ImageDispatcher<I>::invalidate_cache(Context* on_finish) {
+ auto image_ctx = this->m_image_ctx;
+ auto cct = image_ctx->cct;
+ ldout(cct, 5) << dendl;
+
+ auto ctx = new C_InvalidateCache(
+ this, IMAGE_DISPATCH_LAYER_NONE, on_finish);
+ ctx->complete(0);
+}
+
+template <typename I>
+void ImageDispatcher<I>::shut_down(Context* on_finish) {
+ // TODO ensure all IOs are executed via a dispatcher
+ // ensure read-ahead / copy-on-read ops are finished since they are
+ // currently outside dispatcher tracking
+ auto async_op = new AsyncOperation();
+
+ on_finish = new LambdaContext([async_op, on_finish](int r) {
+ async_op->finish_op();
+ delete async_op;
+ on_finish->complete(0);
+ });
+ on_finish = new LambdaContext([this, on_finish](int r) {
+ Dispatcher<I, ImageDispatcherInterface>::shut_down(on_finish);
+ });
+ async_op->start_op(*this->m_image_ctx);
+ async_op->flush(on_finish);
+}
+
+template <typename I>
+void ImageDispatcher<I>::apply_qos_schedule_tick_min(uint64_t tick) {
+ m_qos_image_dispatch->apply_qos_schedule_tick_min(tick);
+}
+
+template <typename I>
+void ImageDispatcher<I>::apply_qos_limit(uint64_t flag, uint64_t limit,
+ uint64_t burst, uint64_t burst_seconds) {
+ m_qos_image_dispatch->apply_qos_limit(flag, limit, burst, burst_seconds);
+}
+
+template <typename I>
+void ImageDispatcher<I>::apply_qos_exclude_ops(uint64_t exclude_ops) {
+ m_qos_image_dispatch->apply_qos_exclude_ops(exclude_ops);
+}
+
+template <typename I>
+bool ImageDispatcher<I>::writes_blocked() const {
+ return m_write_block_dispatch->writes_blocked();
+}
+
+template <typename I>
+int ImageDispatcher<I>::block_writes() {
+ return m_write_block_dispatch->block_writes();
+}
+
+template <typename I>
+void ImageDispatcher<I>::block_writes(Context *on_blocked) {
+ m_write_block_dispatch->block_writes(on_blocked);
+}
+
+template <typename I>
+void ImageDispatcher<I>::unblock_writes() {
+ m_write_block_dispatch->unblock_writes();
+}
+
+template <typename I>
+void ImageDispatcher<I>::wait_on_writes_unblocked(Context *on_unblocked) {
+ m_write_block_dispatch->wait_on_writes_unblocked(on_unblocked);
+}
+
+template <typename I>
+void ImageDispatcher<I>::remap_to_physical(Extents& image_extents,
+ ImageArea area) {
+ std::shared_lock locker{this->m_lock};
+ auto it = this->m_dispatches.find(IMAGE_DISPATCH_LAYER_CRYPTO);
+ if (it == this->m_dispatches.end()) {
+ ceph_assert(area == ImageArea::DATA);
+ return;
+ }
+ auto crypto_image_dispatch = static_cast<crypto::CryptoImageDispatch*>(
+ it->second.dispatch);
+ crypto_image_dispatch->remap_to_physical(image_extents, area);
+}
+
+template <typename I>
+ImageArea ImageDispatcher<I>::remap_to_logical(Extents& image_extents) {
+ std::shared_lock locker{this->m_lock};
+ auto it = this->m_dispatches.find(IMAGE_DISPATCH_LAYER_CRYPTO);
+ if (it == this->m_dispatches.end()) {
+ return ImageArea::DATA;
+ }
+ auto crypto_image_dispatch = static_cast<crypto::CryptoImageDispatch*>(
+ it->second.dispatch);
+ return crypto_image_dispatch->remap_to_logical(image_extents);
+}
+
+template <typename I>
+bool ImageDispatcher<I>::send_dispatch(
+ ImageDispatchInterface* image_dispatch,
+ ImageDispatchSpec* image_dispatch_spec) {
+ if (image_dispatch_spec->tid == 0) {
+ image_dispatch_spec->tid = ++m_next_tid;
+
+ bool finished = preprocess(image_dispatch_spec);
+ if (finished) {
+ return true;
+ }
+ }
+
+ return boost::apply_visitor(
+ SendVisitor{image_dispatch, image_dispatch_spec},
+ image_dispatch_spec->request);
+}
+
+template <typename I>
+bool ImageDispatcher<I>::preprocess(
+ ImageDispatchSpec* image_dispatch_spec) {
+ return boost::apply_visitor(
+ PreprocessVisitor{this, image_dispatch_spec},
+ image_dispatch_spec->request);
+}
+
+} // namespace io
+} // namespace librbd
+
+template class librbd::io::ImageDispatcher<librbd::ImageCtx>;