]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab | |
3 | ||
4 | #ifndef CEPH_LIBRBD_IO_OBJECT_REQUEST_H | |
5 | #define CEPH_LIBRBD_IO_OBJECT_REQUEST_H | |
6 | ||
7 | #include "include/int_types.h" | |
7c673cae FG |
8 | #include "include/buffer.h" |
9 | #include "include/rados/librados.hpp" | |
31f18b77 FG |
10 | #include "common/snap_types.h" |
11 | #include "common/zipkin_trace.h" | |
7c673cae | 12 | #include "librbd/ObjectMap.h" |
b32b8144 | 13 | #include "librbd/io/Types.h" |
31f18b77 | 14 | #include <map> |
7c673cae FG |
15 | |
16 | class Context; | |
11fdf7f2 | 17 | class ObjectExtent; |
7c673cae FG |
18 | |
19 | namespace librbd { | |
20 | ||
21 | struct ImageCtx; | |
22 | ||
23 | namespace io { | |
24 | ||
25 | struct AioCompletion; | |
b32b8144 | 26 | template <typename> class CopyupRequest; |
7c673cae | 27 | |
7c673cae FG |
28 | /** |
29 | * This class represents an I/O operation to a single RBD data object. | |
30 | * Its subclasses encapsulate logic for dealing with special cases | |
31 | * for I/O due to layering. | |
32 | */ | |
33 | template <typename ImageCtxT = ImageCtx> | |
11fdf7f2 | 34 | class ObjectRequest { |
7c673cae | 35 | public: |
11fdf7f2 | 36 | static ObjectRequest* create_write( |
9f95a23c TL |
37 | ImageCtxT *ictx, uint64_t object_no, uint64_t object_off, |
38 | ceph::bufferlist&& data, const ::SnapContext &snapc, int op_flags, | |
39 | const ZTracer::Trace &parent_trace, Context *completion); | |
11fdf7f2 | 40 | static ObjectRequest* create_discard( |
9f95a23c TL |
41 | ImageCtxT *ictx, uint64_t object_no, uint64_t object_off, |
42 | uint64_t object_len, const ::SnapContext &snapc, int discard_flags, | |
11fdf7f2 | 43 | const ZTracer::Trace &parent_trace, Context *completion); |
9f95a23c TL |
44 | static ObjectRequest* create_write_same( |
45 | ImageCtxT *ictx, uint64_t object_no, uint64_t object_off, | |
46 | uint64_t object_len, ceph::bufferlist&& data, const ::SnapContext &snapc, | |
47 | int op_flags, const ZTracer::Trace &parent_trace, Context *completion); | |
11fdf7f2 | 48 | static ObjectRequest* create_compare_and_write( |
9f95a23c TL |
49 | ImageCtxT *ictx, uint64_t object_no, uint64_t object_off, |
50 | ceph::bufferlist&& cmp_data, ceph::bufferlist&& write_data, | |
51 | const ::SnapContext &snapc, uint64_t *mismatch_offset, int op_flags, | |
11fdf7f2 | 52 | const ZTracer::Trace &parent_trace, Context *completion); |
7c673cae | 53 | |
9f95a23c | 54 | ObjectRequest(ImageCtxT *ictx, uint64_t objectno, uint64_t off, uint64_t len, |
b32b8144 FG |
55 | librados::snap_t snap_id, const char *trace_name, |
56 | const ZTracer::Trace &parent_trace, Context *completion); | |
11fdf7f2 | 57 | virtual ~ObjectRequest() { |
31f18b77 FG |
58 | m_trace.event("finish"); |
59 | } | |
7c673cae | 60 | |
b32b8144 FG |
61 | static void add_write_hint(ImageCtxT& image_ctx, |
62 | librados::ObjectWriteOperation *wr); | |
7c673cae | 63 | |
11fdf7f2 | 64 | virtual void send() = 0; |
7c673cae FG |
65 | |
66 | bool has_parent() const { | |
67 | return m_has_parent; | |
68 | } | |
69 | ||
7c673cae | 70 | virtual const char *get_op_type() const = 0; |
7c673cae FG |
71 | |
72 | protected: | |
11fdf7f2 | 73 | bool compute_parent_extents(Extents *parent_extents, bool read_request); |
7c673cae | 74 | |
b32b8144 | 75 | ImageCtxT *m_ictx; |
7c673cae FG |
76 | uint64_t m_object_no, m_object_off, m_object_len; |
77 | librados::snap_t m_snap_id; | |
78 | Context *m_completion; | |
31f18b77 | 79 | ZTracer::Trace m_trace; |
7c673cae | 80 | |
b32b8144 FG |
81 | void async_finish(int r); |
82 | void finish(int r); | |
83 | ||
7c673cae FG |
84 | private: |
85 | bool m_has_parent = false; | |
86 | }; | |
87 | ||
88 | template <typename ImageCtxT = ImageCtx> | |
89 | class ObjectReadRequest : public ObjectRequest<ImageCtxT> { | |
90 | public: | |
7c673cae FG |
91 | typedef std::map<uint64_t, uint64_t> ExtentMap; |
92 | ||
9f95a23c TL |
93 | static ObjectReadRequest* create( |
94 | ImageCtxT *ictx, uint64_t objectno, uint64_t offset, uint64_t len, | |
95 | librados::snap_t snap_id, int op_flags, | |
96 | const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data, | |
97 | ExtentMap* extent_map, Context *completion) { | |
98 | return new ObjectReadRequest(ictx, objectno, offset, len, | |
11fdf7f2 TL |
99 | snap_id, op_flags, parent_trace, read_data, |
100 | extent_map, completion); | |
7c673cae FG |
101 | } |
102 | ||
9f95a23c TL |
103 | ObjectReadRequest( |
104 | ImageCtxT *ictx, uint64_t objectno, uint64_t offset, uint64_t len, | |
105 | librados::snap_t snap_id, int op_flags, | |
106 | const ZTracer::Trace &parent_trace, ceph::bufferlist* read_data, | |
107 | ExtentMap* extent_map, Context *completion); | |
7c673cae | 108 | |
7c673cae | 109 | void send() override; |
7c673cae | 110 | |
7c673cae FG |
111 | const char *get_op_type() const override { |
112 | return "read"; | |
113 | } | |
114 | ||
7c673cae | 115 | private: |
7c673cae | 116 | /** |
b32b8144 | 117 | * @verbatim |
7c673cae | 118 | * |
11fdf7f2 TL |
119 | * <start> |
120 | * | | |
121 | * | | |
122 | * v | |
123 | * READ_OBJECT | |
b32b8144 FG |
124 | * | |
125 | * v (skip if not needed) | |
126 | * READ_PARENT | |
127 | * | | |
128 | * v (skip if not needed) | |
129 | * COPYUP | |
130 | * | | |
131 | * v | |
132 | * <finish> | |
7c673cae | 133 | * |
b32b8144 | 134 | * @endverbatim |
7c673cae | 135 | */ |
7c673cae | 136 | |
b32b8144 | 137 | int m_op_flags; |
7c673cae | 138 | |
11fdf7f2 TL |
139 | ceph::bufferlist* m_read_data; |
140 | ExtentMap* m_extent_map; | |
7c673cae | 141 | |
b32b8144 FG |
142 | void read_object(); |
143 | void handle_read_object(int r); | |
144 | ||
145 | void read_parent(); | |
146 | void handle_read_parent(int r); | |
147 | ||
148 | void copyup(); | |
7c673cae FG |
149 | }; |
150 | ||
b32b8144 FG |
151 | template <typename ImageCtxT = ImageCtx> |
152 | class AbstractObjectWriteRequest : public ObjectRequest<ImageCtxT> { | |
7c673cae | 153 | public: |
9f95a23c TL |
154 | AbstractObjectWriteRequest( |
155 | ImageCtxT *ictx, uint64_t object_no, uint64_t object_off, uint64_t len, | |
156 | const ::SnapContext &snapc, const char *trace_name, | |
157 | const ZTracer::Trace &parent_trace, Context *completion); | |
7c673cae | 158 | |
b32b8144 FG |
159 | virtual bool is_empty_write_op() const { |
160 | return false; | |
7c673cae FG |
161 | } |
162 | ||
b32b8144 FG |
163 | virtual uint8_t get_pre_write_object_map_state() const { |
164 | return OBJECT_EXISTS; | |
165 | } | |
166 | ||
167 | virtual void add_copyup_ops(librados::ObjectWriteOperation *wr) { | |
168 | add_write_ops(wr); | |
169 | } | |
170 | ||
171 | void handle_copyup(int r); | |
172 | ||
7c673cae FG |
173 | void send() override; |
174 | ||
b32b8144 FG |
175 | protected: |
176 | bool m_full_object = false; | |
11fdf7f2 | 177 | bool m_copyup_enabled = true; |
b32b8144 FG |
178 | |
179 | virtual bool is_no_op_for_nonexistent_object() const { | |
180 | return false; | |
181 | } | |
182 | virtual bool is_object_map_update_enabled() const { | |
183 | return true; | |
184 | } | |
185 | virtual bool is_post_copyup_write_required() const { | |
186 | return false; | |
187 | } | |
188 | virtual bool is_non_existent_post_write_object_map_state() const { | |
189 | return false; | |
190 | } | |
191 | ||
192 | virtual void add_write_hint(librados::ObjectWriteOperation *wr); | |
193 | virtual void add_write_ops(librados::ObjectWriteOperation *wr) = 0; | |
194 | ||
195 | virtual int filter_write_result(int r) const { | |
196 | return r; | |
197 | } | |
198 | ||
199 | private: | |
7c673cae | 200 | /** |
b32b8144 | 201 | * @verbatim |
7c673cae | 202 | * |
b32b8144 FG |
203 | * <start> |
204 | * | | |
205 | * v (no-op write request) | |
206 | * DETECT_NO_OP . . . . . . . . . . . . . . . . . . . | |
207 | * | . | |
208 | * v (skip if not required/disabled) . | |
209 | * PRE_UPDATE_OBJECT_MAP . | |
210 | * | . . | |
211 | * | . (child dne) . | |
212 | * | . . . . . . . . . . | |
213 | * | . . | |
214 | * | (post-copyup write) . . | |
215 | * | . . . . . . . . . . . . . . | |
216 | * | . . . . | |
217 | * v v . v . | |
218 | * WRITE . . . . . . . . > COPYUP (if required) . | |
219 | * | | . | |
220 | * |/----------------------/ . | |
221 | * | . | |
222 | * v (skip if not required/disabled) . | |
223 | * POST_UPDATE_OBJECT_MAP . | |
224 | * | . | |
225 | * v . | |
226 | * <finish> < . . . . . . . . . . . . . . . . . . . . | |
7c673cae | 227 | * |
b32b8144 | 228 | * @endverbatim |
7c673cae | 229 | */ |
7c673cae | 230 | |
7c673cae FG |
231 | uint64_t m_snap_seq; |
232 | std::vector<librados::snap_t> m_snaps; | |
7c673cae | 233 | |
b32b8144 FG |
234 | Extents m_parent_extents; |
235 | bool m_object_may_exist = false; | |
b32b8144 | 236 | bool m_copyup_in_progress = false; |
11fdf7f2 TL |
237 | bool m_guarding_migration_write = false; |
238 | ||
239 | void compute_parent_info(); | |
7c673cae | 240 | |
b32b8144 FG |
241 | void pre_write_object_map_update(); |
242 | void handle_pre_write_object_map_update(int r); | |
243 | ||
244 | void write_object(); | |
245 | void handle_write_object(int r); | |
246 | ||
247 | void copyup(); | |
248 | ||
249 | void post_write_object_map_update(); | |
250 | void handle_post_write_object_map_update(int r); | |
7c673cae | 251 | |
7c673cae FG |
252 | }; |
253 | ||
b32b8144 FG |
254 | template <typename ImageCtxT = ImageCtx> |
255 | class ObjectWriteRequest : public AbstractObjectWriteRequest<ImageCtxT> { | |
7c673cae | 256 | public: |
9f95a23c TL |
257 | ObjectWriteRequest( |
258 | ImageCtxT *ictx, uint64_t object_no, uint64_t object_off, | |
259 | ceph::bufferlist&& data, const ::SnapContext &snapc, int op_flags, | |
260 | const ZTracer::Trace &parent_trace, Context *completion) | |
261 | : AbstractObjectWriteRequest<ImageCtxT>(ictx, object_no, object_off, | |
b32b8144 FG |
262 | data.length(), snapc, "write", |
263 | parent_trace, completion), | |
11fdf7f2 | 264 | m_write_data(std::move(data)), m_op_flags(op_flags) { |
7c673cae FG |
265 | } |
266 | ||
b32b8144 | 267 | bool is_empty_write_op() const override { |
7c673cae FG |
268 | return (m_write_data.length() == 0); |
269 | } | |
270 | ||
271 | const char *get_op_type() const override { | |
272 | return "write"; | |
273 | } | |
274 | ||
7c673cae | 275 | protected: |
b32b8144 | 276 | void add_write_ops(librados::ObjectWriteOperation *wr) override; |
7c673cae FG |
277 | |
278 | private: | |
279 | ceph::bufferlist m_write_data; | |
280 | int m_op_flags; | |
281 | }; | |
282 | ||
b32b8144 FG |
283 | template <typename ImageCtxT = ImageCtx> |
284 | class ObjectDiscardRequest : public AbstractObjectWriteRequest<ImageCtxT> { | |
7c673cae | 285 | public: |
9f95a23c TL |
286 | ObjectDiscardRequest( |
287 | ImageCtxT *ictx, uint64_t object_no, uint64_t object_off, | |
288 | uint64_t object_len, const ::SnapContext &snapc, int discard_flags, | |
289 | const ZTracer::Trace &parent_trace, Context *completion) | |
290 | : AbstractObjectWriteRequest<ImageCtxT>(ictx, object_no, object_off, | |
b32b8144 FG |
291 | object_len, snapc, "discard", |
292 | parent_trace, completion), | |
11fdf7f2 | 293 | m_discard_flags(discard_flags) { |
b32b8144 | 294 | if (this->m_full_object) { |
11fdf7f2 TL |
295 | if ((m_discard_flags & OBJECT_DISCARD_FLAG_DISABLE_CLONE_REMOVE) != 0 && |
296 | this->has_parent()) { | |
297 | if (!this->m_copyup_enabled) { | |
298 | // need to hide the parent object instead of child object | |
299 | m_discard_action = DISCARD_ACTION_REMOVE_TRUNCATE; | |
300 | } else { | |
301 | m_discard_action = DISCARD_ACTION_TRUNCATE; | |
302 | } | |
b32b8144 FG |
303 | this->m_object_len = 0; |
304 | } else { | |
305 | m_discard_action = DISCARD_ACTION_REMOVE; | |
306 | } | |
307 | } else if (object_off + object_len == ictx->layout.object_size) { | |
308 | m_discard_action = DISCARD_ACTION_TRUNCATE; | |
7c673cae | 309 | } else { |
b32b8144 | 310 | m_discard_action = DISCARD_ACTION_ZERO; |
7c673cae | 311 | } |
7c673cae FG |
312 | } |
313 | ||
b32b8144 FG |
314 | const char* get_op_type() const override { |
315 | switch (m_discard_action) { | |
316 | case DISCARD_ACTION_REMOVE: | |
317 | return "remove"; | |
318 | case DISCARD_ACTION_REMOVE_TRUNCATE: | |
94b18763 | 319 | return "remove (create+truncate)"; |
b32b8144 FG |
320 | case DISCARD_ACTION_TRUNCATE: |
321 | return "truncate"; | |
322 | case DISCARD_ACTION_ZERO: | |
323 | return "zero"; | |
7c673cae | 324 | } |
11fdf7f2 | 325 | ceph_abort(); |
b32b8144 | 326 | return nullptr; |
7c673cae FG |
327 | } |
328 | ||
b32b8144 FG |
329 | uint8_t get_pre_write_object_map_state() const override { |
330 | if (m_discard_action == DISCARD_ACTION_REMOVE) { | |
331 | return OBJECT_PENDING; | |
7c673cae | 332 | } |
b32b8144 | 333 | return OBJECT_EXISTS; |
7c673cae FG |
334 | } |
335 | ||
336 | protected: | |
b32b8144 FG |
337 | bool is_no_op_for_nonexistent_object() const override { |
338 | return (!this->has_parent()); | |
7c673cae | 339 | } |
b32b8144 | 340 | bool is_object_map_update_enabled() const override { |
11fdf7f2 TL |
341 | return ( |
342 | (m_discard_flags & OBJECT_DISCARD_FLAG_DISABLE_OBJECT_MAP_UPDATE) == 0); | |
7c673cae | 343 | } |
b32b8144 FG |
344 | bool is_non_existent_post_write_object_map_state() const override { |
345 | return (m_discard_action == DISCARD_ACTION_REMOVE); | |
7c673cae FG |
346 | } |
347 | ||
b32b8144 FG |
348 | void add_write_hint(librados::ObjectWriteOperation *wr) override { |
349 | // no hint for discard | |
7c673cae | 350 | } |
7c673cae | 351 | |
b32b8144 FG |
352 | void add_write_ops(librados::ObjectWriteOperation *wr) override { |
353 | switch (m_discard_action) { | |
354 | case DISCARD_ACTION_REMOVE: | |
355 | wr->remove(); | |
356 | break; | |
357 | case DISCARD_ACTION_REMOVE_TRUNCATE: | |
94b18763 FG |
358 | wr->create(false); |
359 | // fall through | |
b32b8144 FG |
360 | case DISCARD_ACTION_TRUNCATE: |
361 | wr->truncate(this->m_object_off); | |
362 | break; | |
363 | case DISCARD_ACTION_ZERO: | |
364 | wr->zero(this->m_object_off, this->m_object_len); | |
365 | break; | |
366 | default: | |
11fdf7f2 | 367 | ceph_abort(); |
b32b8144 FG |
368 | break; |
369 | } | |
7c673cae FG |
370 | } |
371 | ||
b32b8144 FG |
372 | private: |
373 | enum DiscardAction { | |
374 | DISCARD_ACTION_REMOVE, | |
375 | DISCARD_ACTION_REMOVE_TRUNCATE, | |
376 | DISCARD_ACTION_TRUNCATE, | |
377 | DISCARD_ACTION_ZERO | |
378 | }; | |
7c673cae | 379 | |
b32b8144 | 380 | DiscardAction m_discard_action; |
11fdf7f2 | 381 | int m_discard_flags; |
31f18b77 | 382 | |
7c673cae FG |
383 | }; |
384 | ||
b32b8144 FG |
385 | template <typename ImageCtxT = ImageCtx> |
386 | class ObjectWriteSameRequest : public AbstractObjectWriteRequest<ImageCtxT> { | |
7c673cae | 387 | public: |
9f95a23c TL |
388 | ObjectWriteSameRequest( |
389 | ImageCtxT *ictx, uint64_t object_no, uint64_t object_off, | |
390 | uint64_t object_len, ceph::bufferlist&& data, const ::SnapContext &snapc, | |
391 | int op_flags, const ZTracer::Trace &parent_trace, Context *completion) | |
392 | : AbstractObjectWriteRequest<ImageCtxT>(ictx, object_no, object_off, | |
b32b8144 FG |
393 | object_len, snapc, "writesame", |
394 | parent_trace, completion), | |
11fdf7f2 | 395 | m_write_data(std::move(data)), m_op_flags(op_flags) { |
7c673cae FG |
396 | } |
397 | ||
398 | const char *get_op_type() const override { | |
399 | return "writesame"; | |
400 | } | |
401 | ||
7c673cae | 402 | protected: |
b32b8144 | 403 | void add_write_ops(librados::ObjectWriteOperation *wr) override; |
7c673cae FG |
404 | |
405 | private: | |
406 | ceph::bufferlist m_write_data; | |
407 | int m_op_flags; | |
408 | }; | |
409 | ||
b32b8144 FG |
410 | template <typename ImageCtxT = ImageCtx> |
411 | class ObjectCompareAndWriteRequest : public AbstractObjectWriteRequest<ImageCtxT> { | |
c07f9fc5 | 412 | public: |
9f95a23c TL |
413 | ObjectCompareAndWriteRequest( |
414 | ImageCtxT *ictx, uint64_t object_no, uint64_t object_off, | |
415 | ceph::bufferlist&& cmp_bl, ceph::bufferlist&& write_bl, | |
416 | const ::SnapContext &snapc, uint64_t *mismatch_offset, int op_flags, | |
417 | const ZTracer::Trace &parent_trace, Context *completion) | |
418 | : AbstractObjectWriteRequest<ImageCtxT>(ictx, object_no, object_off, | |
b32b8144 FG |
419 | cmp_bl.length(), snapc, |
420 | "compare_and_write", parent_trace, | |
421 | completion), | |
11fdf7f2 | 422 | m_cmp_bl(std::move(cmp_bl)), m_write_bl(std::move(write_bl)), |
c07f9fc5 FG |
423 | m_mismatch_offset(mismatch_offset), m_op_flags(op_flags) { |
424 | } | |
425 | ||
426 | const char *get_op_type() const override { | |
427 | return "compare_and_write"; | |
428 | } | |
429 | ||
b32b8144 FG |
430 | void add_copyup_ops(librados::ObjectWriteOperation *wr) override { |
431 | // no-op on copyup | |
c07f9fc5 FG |
432 | } |
433 | ||
c07f9fc5 | 434 | protected: |
b32b8144 FG |
435 | virtual bool is_post_copyup_write_required() const { |
436 | return true; | |
437 | } | |
438 | ||
439 | void add_write_ops(librados::ObjectWriteOperation *wr) override; | |
c07f9fc5 | 440 | |
b32b8144 | 441 | int filter_write_result(int r) const override; |
c07f9fc5 FG |
442 | |
443 | private: | |
444 | ceph::bufferlist m_cmp_bl; | |
445 | ceph::bufferlist m_write_bl; | |
446 | uint64_t *m_mismatch_offset; | |
447 | int m_op_flags; | |
448 | }; | |
449 | ||
7c673cae FG |
450 | } // namespace io |
451 | } // namespace librbd | |
452 | ||
453 | extern template class librbd::io::ObjectRequest<librbd::ImageCtx>; | |
454 | extern template class librbd::io::ObjectReadRequest<librbd::ImageCtx>; | |
b32b8144 FG |
455 | extern template class librbd::io::AbstractObjectWriteRequest<librbd::ImageCtx>; |
456 | extern template class librbd::io::ObjectWriteRequest<librbd::ImageCtx>; | |
457 | extern template class librbd::io::ObjectDiscardRequest<librbd::ImageCtx>; | |
458 | extern template class librbd::io::ObjectWriteSameRequest<librbd::ImageCtx>; | |
459 | extern template class librbd::io::ObjectCompareAndWriteRequest<librbd::ImageCtx>; | |
7c673cae FG |
460 | |
461 | #endif // CEPH_LIBRBD_IO_OBJECT_REQUEST_H |