]>
Commit | Line | Data |
---|---|---|
11fdf7f2 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #include "librbd/io/Utils.h" | |
f91f0fd5 | 5 | #include "common/dout.h" |
11fdf7f2 | 6 | #include "include/buffer.h" |
f91f0fd5 | 7 | #include "include/rados/librados.hpp" |
f67539c2 TL |
8 | #include "include/neorados/RADOS.hpp" |
9 | #include "librbd/internal.h" | |
10 | #include "librbd/Utils.h" | |
f91f0fd5 | 11 | #include "librbd/io/AioCompletion.h" |
f67539c2 TL |
12 | #include "librbd/io/ImageDispatchSpec.h" |
13 | #include "librbd/io/ObjectRequest.h" | |
14 | #include "librbd/io/ImageDispatcherInterface.h" | |
11fdf7f2 | 15 | #include "osd/osd_types.h" |
f91f0fd5 TL |
16 | #include "osdc/Striper.h" |
17 | ||
18 | #define dout_subsys ceph_subsys_rbd | |
19 | #undef dout_prefix | |
20 | #define dout_prefix *_dout << "librbd::io::util: " << __func__ << ": " | |
11fdf7f2 TL |
21 | |
22 | namespace librbd { | |
23 | namespace io { | |
24 | namespace util { | |
25 | ||
f67539c2 TL |
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(); | |
37 | ||
38 | if (flags & librados::OPERATION_BALANCE_READS) | |
39 | op->balance_reads(); | |
40 | if (flags & librados::OPERATION_LOCALIZE_READS) | |
41 | op->localize_reads(); | |
42 | } | |
43 | ||
11fdf7f2 | 44 | bool assemble_write_same_extent( |
9f95a23c | 45 | const LightweightObjectExtent &object_extent, const ceph::bufferlist& data, |
11fdf7f2 TL |
46 | ceph::bufferlist *ws_data, bool force_write) { |
47 | size_t data_len = data.length(); | |
48 | ||
49 | if (!force_write) { | |
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; | |
54 | break; | |
55 | } | |
56 | } | |
57 | ||
58 | if (may_writesame) { | |
59 | ws_data->append(data); | |
60 | return true; | |
61 | } | |
62 | } | |
63 | ||
64 | for (auto& q : object_extent.buffer_extents) { | |
65 | bufferlist sub_bl; | |
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; | |
73 | if (sub_off) { | |
74 | sub_off = 0; | |
75 | sub_len = data_len; | |
76 | } | |
77 | } | |
78 | if (extent_left) { | |
79 | sub_bl.substr_of(data, sub_off, extent_left); | |
80 | ws_data->claim_append(sub_bl); | |
81 | } | |
82 | } | |
83 | return false; | |
84 | } | |
85 | ||
f91f0fd5 | 86 | template <typename I> |
1e59de90 | 87 | void read_parent(I *image_ctx, uint64_t object_no, ReadExtents* read_extents, |
f67539c2 | 88 | librados::snap_t snap_id, const ZTracer::Trace &trace, |
f91f0fd5 TL |
89 | Context* on_finish) { |
90 | ||
91 | auto cct = image_ctx->cct; | |
92 | ||
93 | std::shared_lock image_locker{image_ctx->image_lock}; | |
94 | ||
f91f0fd5 | 95 | Extents parent_extents; |
1e59de90 TL |
96 | ImageArea area; |
97 | uint64_t raw_overlap = 0; | |
f91f0fd5 | 98 | uint64_t object_overlap = 0; |
1e59de90 TL |
99 | image_ctx->get_parent_overlap(snap_id, &raw_overlap); |
100 | if (raw_overlap > 0) { | |
101 | // calculate reverse mapping onto the parent image | |
102 | Extents extents; | |
103 | for (const auto& extent : *read_extents) { | |
104 | extents.emplace_back(extent.offset, extent.length); | |
105 | } | |
106 | std::tie(parent_extents, area) = object_to_area_extents(image_ctx, | |
107 | object_no, extents); | |
108 | object_overlap = image_ctx->prune_parent_extents(parent_extents, area, | |
109 | raw_overlap, false); | |
f91f0fd5 | 110 | } |
f91f0fd5 TL |
111 | if (object_overlap == 0) { |
112 | image_locker.unlock(); | |
113 | ||
114 | on_finish->complete(-ENOENT); | |
115 | return; | |
116 | } | |
117 | ||
118 | ldout(cct, 20) << dendl; | |
119 | ||
f67539c2 | 120 | ceph::bufferlist* parent_read_bl; |
1e59de90 | 121 | if (read_extents->size() > 1) { |
f67539c2 | 122 | auto parent_comp = new ReadResult::C_ObjectReadMergedExtents( |
1e59de90 | 123 | cct, read_extents, on_finish); |
f67539c2 TL |
124 | parent_read_bl = &parent_comp->bl; |
125 | on_finish = parent_comp; | |
126 | } else { | |
1e59de90 | 127 | parent_read_bl = &read_extents->front().bl; |
f67539c2 TL |
128 | } |
129 | ||
f91f0fd5 TL |
130 | auto comp = AioCompletion::create_and_start(on_finish, image_ctx->parent, |
131 | AIO_TYPE_READ); | |
1e59de90 TL |
132 | ldout(cct, 20) << "completion=" << comp |
133 | << " parent_extents=" << parent_extents | |
134 | << " area=" << area << dendl; | |
f67539c2 TL |
135 | auto req = io::ImageDispatchSpec::create_read( |
136 | *image_ctx->parent, io::IMAGE_DISPATCH_LAYER_INTERNAL_START, comp, | |
1e59de90 | 137 | std::move(parent_extents), area, ReadResult{parent_read_bl}, |
f67539c2 TL |
138 | image_ctx->parent->get_data_io_context(), 0, 0, trace); |
139 | req->send(); | |
140 | } | |
f91f0fd5 | 141 | |
f67539c2 | 142 | template <typename I> |
1e59de90 | 143 | int clip_request(I* image_ctx, Extents* image_extents, ImageArea area) { |
f67539c2 TL |
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), | |
1e59de90 | 148 | image_extent.first, &clip_len, area); |
f67539c2 TL |
149 | if (r < 0) { |
150 | return r; | |
151 | } | |
152 | ||
153 | image_extent.second = clip_len; | |
154 | } | |
155 | return 0; | |
156 | } | |
157 | ||
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; | |
162 | bufferlist out_bl; | |
163 | ||
164 | destriper.add_partial_sparse_result(cct, std::move(*bl), extent_map, bl_off, | |
165 | {{0, out_bl_len}}); | |
166 | destriper.assemble_result(cct, out_bl, true); | |
167 | *bl = out_bl; | |
168 | } | |
169 | ||
170 | template <typename I> | |
171 | bool trigger_copyup(I* image_ctx, uint64_t object_no, IOContext io_context, | |
172 | Context* on_finish) { | |
173 | bufferlist bl; | |
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()) { | |
178 | delete req; | |
179 | return false; | |
180 | } | |
181 | ||
182 | req->send(); | |
183 | return true; | |
184 | } | |
185 | ||
186 | template <typename I> | |
1e59de90 TL |
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) { | |
f67539c2 | 190 | Extents extents = {{offset, length}}; |
1e59de90 | 191 | image_ctx->io_image_dispatcher->remap_to_physical(extents, area); |
f67539c2 TL |
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); | |
195 | } | |
196 | } | |
197 | ||
198 | template <typename I> | |
1e59de90 TL |
199 | std::pair<Extents, ImageArea> object_to_area_extents( |
200 | I* image_ctx, uint64_t object_no, const Extents& object_extents) { | |
201 | Extents extents; | |
202 | for (auto [off, len] : object_extents) { | |
203 | Striper::extent_to_file(image_ctx->cct, &image_ctx->layout, object_no, off, | |
204 | len, extents); | |
205 | } | |
206 | auto area = image_ctx->io_image_dispatcher->remap_to_logical(extents); | |
207 | return {std::move(extents), area}; | |
f67539c2 TL |
208 | } |
209 | ||
210 | template <typename I> | |
1e59de90 TL |
211 | uint64_t area_to_raw_offset(const I& image_ctx, uint64_t offset, |
212 | ImageArea area) { | |
213 | Extents extents = {{offset, 0}}; | |
214 | image_ctx.io_image_dispatcher->remap_to_physical(extents, area); | |
f67539c2 | 215 | return extents[0].first; |
f91f0fd5 TL |
216 | } |
217 | ||
1e59de90 TL |
218 | template <typename I> |
219 | std::pair<uint64_t, ImageArea> raw_to_area_offset(const I& image_ctx, | |
220 | uint64_t offset) { | |
221 | Extents extents = {{offset, 0}}; | |
222 | auto area = image_ctx.io_image_dispatcher->remap_to_logical(extents); | |
223 | return {extents[0].first, area}; | |
224 | } | |
225 | ||
11fdf7f2 TL |
226 | } // namespace util |
227 | } // namespace io | |
228 | } // namespace librbd | |
229 | ||
f91f0fd5 | 230 | template void librbd::io::util::read_parent( |
f67539c2 TL |
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( | |
1e59de90 | 234 | librbd::ImageCtx* image_ctx, Extents* image_extents, ImageArea area); |
f67539c2 TL |
235 | template bool librbd::io::util::trigger_copyup( |
236 | librbd::ImageCtx *image_ctx, uint64_t object_no, IOContext io_context, | |
237 | Context* on_finish); | |
1e59de90 TL |
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>; |