summaryrefslogtreecommitdiffstats
path: root/src/librbd/io/Utils.cc
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/librbd/io/Utils.cc249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/librbd/io/Utils.cc b/src/librbd/io/Utils.cc
new file mode 100644
index 000000000..63d587206
--- /dev/null
+++ b/src/librbd/io/Utils.cc
@@ -0,0 +1,249 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/io/Utils.h"
+#include "common/dout.h"
+#include "include/buffer.h"
+#include "include/rados/librados.hpp"
+#include "include/neorados/RADOS.hpp"
+#include "librbd/internal.h"
+#include "librbd/Utils.h"
+#include "librbd/io/AioCompletion.h"
+#include "librbd/io/ImageDispatchSpec.h"
+#include "librbd/io/ObjectRequest.h"
+#include "librbd/io/ImageDispatcherInterface.h"
+#include "osd/osd_types.h"
+#include "osdc/Striper.h"
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::io::util: " << __func__ << ": "
+
+namespace librbd {
+namespace io {
+namespace util {
+
+void apply_op_flags(uint32_t op_flags, uint32_t flags, neorados::Op* op) {
+ if (op_flags & LIBRADOS_OP_FLAG_FADVISE_RANDOM)
+ op->set_fadvise_random();
+ if (op_flags & LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL)
+ op->set_fadvise_sequential();
+ if (op_flags & LIBRADOS_OP_FLAG_FADVISE_WILLNEED)
+ op->set_fadvise_willneed();
+ if (op_flags & LIBRADOS_OP_FLAG_FADVISE_DONTNEED)
+ op->set_fadvise_dontneed();
+ if (op_flags & LIBRADOS_OP_FLAG_FADVISE_NOCACHE)
+ op->set_fadvise_nocache();
+
+ if (flags & librados::OPERATION_BALANCE_READS)
+ op->balance_reads();
+ if (flags & librados::OPERATION_LOCALIZE_READS)
+ op->localize_reads();
+}
+
+bool assemble_write_same_extent(
+ const LightweightObjectExtent &object_extent, const ceph::bufferlist& data,
+ ceph::bufferlist *ws_data, bool force_write) {
+ size_t data_len = data.length();
+
+ if (!force_write) {
+ bool may_writesame = true;
+ for (auto& q : object_extent.buffer_extents) {
+ if (!(q.first % data_len == 0 && q.second % data_len == 0)) {
+ may_writesame = false;
+ break;
+ }
+ }
+
+ if (may_writesame) {
+ ws_data->append(data);
+ return true;
+ }
+ }
+
+ for (auto& q : object_extent.buffer_extents) {
+ bufferlist sub_bl;
+ uint64_t sub_off = q.first % data_len;
+ uint64_t sub_len = data_len - sub_off;
+ uint64_t extent_left = q.second;
+ while (extent_left >= sub_len) {
+ sub_bl.substr_of(data, sub_off, sub_len);
+ ws_data->claim_append(sub_bl);
+ extent_left -= sub_len;
+ if (sub_off) {
+ sub_off = 0;
+ sub_len = data_len;
+ }
+ }
+ if (extent_left) {
+ sub_bl.substr_of(data, sub_off, extent_left);
+ ws_data->claim_append(sub_bl);
+ }
+ }
+ return false;
+}
+
+template <typename I>
+void read_parent(I *image_ctx, uint64_t object_no, ReadExtents* read_extents,
+ librados::snap_t snap_id, const ZTracer::Trace &trace,
+ Context* on_finish) {
+
+ auto cct = image_ctx->cct;
+
+ std::shared_lock image_locker{image_ctx->image_lock};
+
+ Extents parent_extents;
+ ImageArea area;
+ uint64_t raw_overlap = 0;
+ uint64_t object_overlap = 0;
+ image_ctx->get_parent_overlap(snap_id, &raw_overlap);
+ if (raw_overlap > 0) {
+ // calculate reverse mapping onto the parent image
+ Extents extents;
+ for (const auto& extent : *read_extents) {
+ extents.emplace_back(extent.offset, extent.length);
+ }
+ std::tie(parent_extents, area) = object_to_area_extents(image_ctx,
+ object_no, extents);
+ object_overlap = image_ctx->prune_parent_extents(parent_extents, area,
+ raw_overlap, false);
+ }
+ if (object_overlap == 0) {
+ image_locker.unlock();
+
+ on_finish->complete(-ENOENT);
+ return;
+ }
+
+ ldout(cct, 20) << dendl;
+
+ ceph::bufferlist* parent_read_bl;
+ if (read_extents->size() > 1) {
+ auto parent_comp = new ReadResult::C_ObjectReadMergedExtents(
+ cct, read_extents, on_finish);
+ parent_read_bl = &parent_comp->bl;
+ on_finish = parent_comp;
+ } else {
+ parent_read_bl = &read_extents->front().bl;
+ }
+
+ auto comp = AioCompletion::create_and_start(on_finish, image_ctx->parent,
+ AIO_TYPE_READ);
+ ldout(cct, 20) << "completion=" << comp
+ << " parent_extents=" << parent_extents
+ << " area=" << area << dendl;
+ auto req = io::ImageDispatchSpec::create_read(
+ *image_ctx->parent, io::IMAGE_DISPATCH_LAYER_INTERNAL_START, comp,
+ std::move(parent_extents), area, ReadResult{parent_read_bl},
+ image_ctx->parent->get_data_io_context(), 0, 0, trace);
+ req->send();
+}
+
+template <typename I>
+int clip_request(I* image_ctx, Extents* image_extents, ImageArea area) {
+ std::shared_lock image_locker{image_ctx->image_lock};
+ for (auto &image_extent : *image_extents) {
+ auto clip_len = image_extent.second;
+ int r = clip_io(librbd::util::get_image_ctx(image_ctx),
+ image_extent.first, &clip_len, area);
+ if (r < 0) {
+ return r;
+ }
+
+ image_extent.second = clip_len;
+ }
+ return 0;
+}
+
+void unsparsify(CephContext* cct, ceph::bufferlist* bl,
+ const Extents& extent_map, uint64_t bl_off,
+ uint64_t out_bl_len) {
+ Striper::StripedReadResult destriper;
+ bufferlist out_bl;
+
+ destriper.add_partial_sparse_result(cct, std::move(*bl), extent_map, bl_off,
+ {{0, out_bl_len}});
+ destriper.assemble_result(cct, out_bl, true);
+ *bl = out_bl;
+}
+
+template <typename I>
+bool trigger_copyup(I* image_ctx, uint64_t object_no, IOContext io_context,
+ Context* on_finish) {
+ bufferlist bl;
+ auto req = new ObjectWriteRequest<I>(
+ image_ctx, object_no, 0, std::move(bl), io_context, 0, 0,
+ std::nullopt, {}, on_finish);
+ if (!req->has_parent()) {
+ delete req;
+ return false;
+ }
+
+ req->send();
+ return true;
+}
+
+template <typename I>
+void area_to_object_extents(I* image_ctx, uint64_t offset, uint64_t length,
+ ImageArea area, uint64_t buffer_offset,
+ striper::LightweightObjectExtents* object_extents) {
+ Extents extents = {{offset, length}};
+ image_ctx->io_image_dispatcher->remap_to_physical(extents, area);
+ for (auto [off, len] : extents) {
+ Striper::file_to_extents(image_ctx->cct, &image_ctx->layout, off, len, 0,
+ buffer_offset, object_extents);
+ }
+}
+
+template <typename I>
+std::pair<Extents, ImageArea> object_to_area_extents(
+ I* image_ctx, uint64_t object_no, const Extents& object_extents) {
+ Extents extents;
+ for (auto [off, len] : object_extents) {
+ Striper::extent_to_file(image_ctx->cct, &image_ctx->layout, object_no, off,
+ len, extents);
+ }
+ auto area = image_ctx->io_image_dispatcher->remap_to_logical(extents);
+ return {std::move(extents), area};
+}
+
+template <typename I>
+uint64_t area_to_raw_offset(const I& image_ctx, uint64_t offset,
+ ImageArea area) {
+ Extents extents = {{offset, 0}};
+ image_ctx.io_image_dispatcher->remap_to_physical(extents, area);
+ return extents[0].first;
+}
+
+template <typename I>
+std::pair<uint64_t, ImageArea> raw_to_area_offset(const I& image_ctx,
+ uint64_t offset) {
+ Extents extents = {{offset, 0}};
+ auto area = image_ctx.io_image_dispatcher->remap_to_logical(extents);
+ return {extents[0].first, area};
+}
+
+} // namespace util
+} // namespace io
+} // namespace librbd
+
+template void librbd::io::util::read_parent(
+ librbd::ImageCtx *image_ctx, uint64_t object_no, ReadExtents* extents,
+ librados::snap_t snap_id, const ZTracer::Trace &trace, Context* on_finish);
+template int librbd::io::util::clip_request(
+ librbd::ImageCtx* image_ctx, Extents* image_extents, ImageArea area);
+template bool librbd::io::util::trigger_copyup(
+ librbd::ImageCtx *image_ctx, uint64_t object_no, IOContext io_context,
+ Context* on_finish);
+template void librbd::io::util::area_to_object_extents(
+ librbd::ImageCtx* image_ctx, uint64_t offset, uint64_t length,
+ ImageArea area, uint64_t buffer_offset,
+ striper::LightweightObjectExtents* object_extents);
+template auto librbd::io::util::object_to_area_extents(
+ librbd::ImageCtx* image_ctx, uint64_t object_no, const Extents& extents)
+ -> std::pair<Extents, ImageArea>;
+template uint64_t librbd::io::util::area_to_raw_offset(
+ const librbd::ImageCtx& image_ctx, uint64_t offset, ImageArea area);
+template auto librbd::io::util::raw_to_area_offset(
+ const librbd::ImageCtx& image_ctx, uint64_t offset)
+ -> std::pair<uint64_t, ImageArea>;