1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "librbd/io/Utils.h"
5 #include "common/dout.h"
6 #include "include/buffer.h"
7 #include "include/rados/librados.hpp"
8 #include "include/neorados/RADOS.hpp"
9 #include "librbd/internal.h"
10 #include "librbd/Utils.h"
11 #include "librbd/io/AioCompletion.h"
12 #include "librbd/io/ImageDispatchSpec.h"
13 #include "librbd/io/ObjectRequest.h"
14 #include "librbd/io/ImageDispatcherInterface.h"
15 #include "osd/osd_types.h"
16 #include "osdc/Striper.h"
18 #define dout_subsys ceph_subsys_rbd
20 #define dout_prefix *_dout << "librbd::io::util: " << __func__ << ": "
26 void apply_op_flags(uint32_t op_flags
, uint32_t flags
, neorados::Op
* op
) {
27 if (op_flags
& LIBRADOS_OP_FLAG_FADVISE_RANDOM
)
28 op
->set_fadvise_random();
29 if (op_flags
& LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
)
30 op
->set_fadvise_sequential();
31 if (op_flags
& LIBRADOS_OP_FLAG_FADVISE_WILLNEED
)
32 op
->set_fadvise_willneed();
33 if (op_flags
& LIBRADOS_OP_FLAG_FADVISE_DONTNEED
)
34 op
->set_fadvise_dontneed();
35 if (op_flags
& LIBRADOS_OP_FLAG_FADVISE_NOCACHE
)
36 op
->set_fadvise_nocache();
38 if (flags
& librados::OPERATION_BALANCE_READS
)
40 if (flags
& librados::OPERATION_LOCALIZE_READS
)
44 bool assemble_write_same_extent(
45 const LightweightObjectExtent
&object_extent
, const ceph::bufferlist
& data
,
46 ceph::bufferlist
*ws_data
, bool force_write
) {
47 size_t data_len
= data
.length();
50 bool may_writesame
= true;
51 for (auto& q
: object_extent
.buffer_extents
) {
52 if (!(q
.first
% data_len
== 0 && q
.second
% data_len
== 0)) {
53 may_writesame
= false;
59 ws_data
->append(data
);
64 for (auto& q
: object_extent
.buffer_extents
) {
66 uint64_t sub_off
= q
.first
% data_len
;
67 uint64_t sub_len
= data_len
- sub_off
;
68 uint64_t extent_left
= q
.second
;
69 while (extent_left
>= sub_len
) {
70 sub_bl
.substr_of(data
, sub_off
, sub_len
);
71 ws_data
->claim_append(sub_bl
);
72 extent_left
-= sub_len
;
79 sub_bl
.substr_of(data
, sub_off
, extent_left
);
80 ws_data
->claim_append(sub_bl
);
87 void read_parent(I
*image_ctx
, uint64_t object_no
, ReadExtents
* read_extents
,
88 librados::snap_t snap_id
, const ZTracer::Trace
&trace
,
91 auto cct
= image_ctx
->cct
;
93 std::shared_lock image_locker
{image_ctx
->image_lock
};
95 Extents parent_extents
;
97 uint64_t raw_overlap
= 0;
98 uint64_t object_overlap
= 0;
99 image_ctx
->get_parent_overlap(snap_id
, &raw_overlap
);
100 if (raw_overlap
> 0) {
101 // calculate reverse mapping onto the parent image
103 for (const auto& extent
: *read_extents
) {
104 extents
.emplace_back(extent
.offset
, extent
.length
);
106 std::tie(parent_extents
, area
) = object_to_area_extents(image_ctx
,
108 object_overlap
= image_ctx
->prune_parent_extents(parent_extents
, area
,
111 if (object_overlap
== 0) {
112 image_locker
.unlock();
114 on_finish
->complete(-ENOENT
);
118 ldout(cct
, 20) << dendl
;
120 ceph::bufferlist
* parent_read_bl
;
121 if (read_extents
->size() > 1) {
122 auto parent_comp
= new ReadResult::C_ObjectReadMergedExtents(
123 cct
, read_extents
, on_finish
);
124 parent_read_bl
= &parent_comp
->bl
;
125 on_finish
= parent_comp
;
127 parent_read_bl
= &read_extents
->front().bl
;
130 auto comp
= AioCompletion::create_and_start(on_finish
, image_ctx
->parent
,
132 ldout(cct
, 20) << "completion=" << comp
133 << " parent_extents=" << parent_extents
134 << " area=" << area
<< dendl
;
135 auto req
= io::ImageDispatchSpec::create_read(
136 *image_ctx
->parent
, io::IMAGE_DISPATCH_LAYER_INTERNAL_START
, comp
,
137 std::move(parent_extents
), area
, ReadResult
{parent_read_bl
},
138 image_ctx
->parent
->get_data_io_context(), 0, 0, trace
);
142 template <typename I
>
143 int clip_request(I
* image_ctx
, Extents
* image_extents
, ImageArea area
) {
144 std::shared_lock image_locker
{image_ctx
->image_lock
};
145 for (auto &image_extent
: *image_extents
) {
146 auto clip_len
= image_extent
.second
;
147 int r
= clip_io(librbd::util::get_image_ctx(image_ctx
),
148 image_extent
.first
, &clip_len
, area
);
153 image_extent
.second
= clip_len
;
158 void unsparsify(CephContext
* cct
, ceph::bufferlist
* bl
,
159 const Extents
& extent_map
, uint64_t bl_off
,
160 uint64_t out_bl_len
) {
161 Striper::StripedReadResult destriper
;
164 destriper
.add_partial_sparse_result(cct
, std::move(*bl
), extent_map
, bl_off
,
166 destriper
.assemble_result(cct
, out_bl
, true);
170 template <typename I
>
171 bool trigger_copyup(I
* image_ctx
, uint64_t object_no
, IOContext io_context
,
172 Context
* on_finish
) {
174 auto req
= new ObjectWriteRequest
<I
>(
175 image_ctx
, object_no
, 0, std::move(bl
), io_context
, 0, 0,
176 std::nullopt
, {}, on_finish
);
177 if (!req
->has_parent()) {
186 template <typename I
>
187 void area_to_object_extents(I
* image_ctx
, uint64_t offset
, uint64_t length
,
188 ImageArea area
, uint64_t buffer_offset
,
189 striper::LightweightObjectExtents
* object_extents
) {
190 Extents extents
= {{offset
, length
}};
191 image_ctx
->io_image_dispatcher
->remap_to_physical(extents
, area
);
192 for (auto [off
, len
] : extents
) {
193 Striper::file_to_extents(image_ctx
->cct
, &image_ctx
->layout
, off
, len
, 0,
194 buffer_offset
, object_extents
);
198 template <typename I
>
199 std::pair
<Extents
, ImageArea
> object_to_area_extents(
200 I
* image_ctx
, uint64_t object_no
, const Extents
& object_extents
) {
202 for (auto [off
, len
] : object_extents
) {
203 Striper::extent_to_file(image_ctx
->cct
, &image_ctx
->layout
, object_no
, off
,
206 auto area
= image_ctx
->io_image_dispatcher
->remap_to_logical(extents
);
207 return {std::move(extents
), area
};
210 template <typename I
>
211 uint64_t area_to_raw_offset(const I
& image_ctx
, uint64_t offset
,
213 Extents extents
= {{offset
, 0}};
214 image_ctx
.io_image_dispatcher
->remap_to_physical(extents
, area
);
215 return extents
[0].first
;
218 template <typename I
>
219 std::pair
<uint64_t, ImageArea
> raw_to_area_offset(const I
& image_ctx
,
221 Extents extents
= {{offset
, 0}};
222 auto area
= image_ctx
.io_image_dispatcher
->remap_to_logical(extents
);
223 return {extents
[0].first
, area
};
228 } // namespace librbd
230 template void librbd::io::util::read_parent(
231 librbd::ImageCtx
*image_ctx
, uint64_t object_no
, ReadExtents
* extents
,
232 librados::snap_t snap_id
, const ZTracer::Trace
&trace
, Context
* on_finish
);
233 template int librbd::io::util::clip_request(
234 librbd::ImageCtx
* image_ctx
, Extents
* image_extents
, ImageArea area
);
235 template bool librbd::io::util::trigger_copyup(
236 librbd::ImageCtx
*image_ctx
, uint64_t object_no
, IOContext io_context
,
238 template void librbd::io::util::area_to_object_extents(
239 librbd::ImageCtx
* image_ctx
, uint64_t offset
, uint64_t length
,
240 ImageArea area
, uint64_t buffer_offset
,
241 striper::LightweightObjectExtents
* object_extents
);
242 template auto librbd::io::util::object_to_area_extents(
243 librbd::ImageCtx
* image_ctx
, uint64_t object_no
, const Extents
& extents
)
244 -> std::pair
<Extents
, ImageArea
>;
245 template uint64_t librbd::io::util::area_to_raw_offset(
246 const librbd::ImageCtx
& image_ctx
, uint64_t offset
, ImageArea area
);
247 template auto librbd::io::util::raw_to_area_offset(
248 const librbd::ImageCtx
& image_ctx
, uint64_t offset
)
249 -> std::pair
<uint64_t, ImageArea
>;