]>
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 | #include "librbd/io/ObjectRequest.h" | |
5 | #include "common/ceph_context.h" | |
6 | #include "common/dout.h" | |
7 | #include "common/errno.h" | |
9f95a23c | 8 | #include "common/ceph_mutex.h" |
7c673cae FG |
9 | #include "common/WorkQueue.h" |
10 | #include "include/Context.h" | |
c07f9fc5 | 11 | #include "include/err.h" |
11fdf7f2 | 12 | #include "osd/osd_types.h" |
7c673cae FG |
13 | |
14 | #include "librbd/ExclusiveLock.h" | |
15 | #include "librbd/ImageCtx.h" | |
16 | #include "librbd/ObjectMap.h" | |
17 | #include "librbd/Utils.h" | |
18 | #include "librbd/io/AioCompletion.h" | |
19 | #include "librbd/io/CopyupRequest.h" | |
20 | #include "librbd/io/ImageRequest.h" | |
21 | #include "librbd/io/ReadResult.h" | |
22 | ||
23 | #include <boost/bind.hpp> | |
24 | #include <boost/optional.hpp> | |
25 | ||
26 | #define dout_subsys ceph_subsys_rbd | |
27 | #undef dout_prefix | |
9f95a23c TL |
28 | #define dout_prefix *_dout << "librbd::io::ObjectRequest: " << this \ |
29 | << " " << __func__ << ": " \ | |
30 | << data_object_name(this->m_ictx, \ | |
31 | this->m_object_no) << " " | |
7c673cae FG |
32 | |
33 | namespace librbd { | |
34 | namespace io { | |
35 | ||
9f95a23c TL |
36 | using librbd::util::data_object_name; |
37 | ||
b32b8144 | 38 | namespace { |
7c673cae FG |
39 | |
40 | template <typename I> | |
b32b8144 | 41 | inline bool is_copy_on_read(I *ictx, librados::snap_t snap_id) { |
9f95a23c | 42 | std::shared_lock image_locker{ictx->image_lock}; |
b32b8144 FG |
43 | return (ictx->clone_copy_on_read && |
44 | !ictx->read_only && snap_id == CEPH_NOSNAP && | |
45 | (ictx->exclusive_lock == nullptr || | |
46 | ictx->exclusive_lock->is_lock_owner())); | |
7c673cae FG |
47 | } |
48 | ||
b32b8144 | 49 | } // anonymous namespace |
3efd9988 | 50 | |
7c673cae FG |
51 | template <typename I> |
52 | ObjectRequest<I>* | |
9f95a23c TL |
53 | ObjectRequest<I>::create_write( |
54 | I *ictx, uint64_t object_no, uint64_t object_off, ceph::bufferlist&& data, | |
55 | const ::SnapContext &snapc, int op_flags, | |
56 | const ZTracer::Trace &parent_trace, Context *completion) { | |
57 | return new ObjectWriteRequest<I>(ictx, object_no, object_off, | |
11fdf7f2 TL |
58 | std::move(data), snapc, op_flags, |
59 | parent_trace, completion); | |
7c673cae FG |
60 | } |
61 | ||
62 | template <typename I> | |
63 | ObjectRequest<I>* | |
9f95a23c TL |
64 | ObjectRequest<I>::create_discard( |
65 | I *ictx, uint64_t object_no, uint64_t object_off, uint64_t object_len, | |
66 | const ::SnapContext &snapc, int discard_flags, | |
67 | const ZTracer::Trace &parent_trace, Context *completion) { | |
68 | return new ObjectDiscardRequest<I>(ictx, object_no, object_off, | |
11fdf7f2 TL |
69 | object_len, snapc, discard_flags, |
70 | parent_trace, completion); | |
7c673cae FG |
71 | } |
72 | ||
73 | template <typename I> | |
74 | ObjectRequest<I>* | |
9f95a23c TL |
75 | ObjectRequest<I>::create_write_same( |
76 | I *ictx, uint64_t object_no, uint64_t object_off, uint64_t object_len, | |
77 | ceph::bufferlist&& data, const ::SnapContext &snapc, int op_flags, | |
78 | const ZTracer::Trace &parent_trace, Context *completion) { | |
79 | return new ObjectWriteSameRequest<I>(ictx, object_no, object_off, | |
11fdf7f2 TL |
80 | object_len, std::move(data), snapc, |
81 | op_flags, parent_trace, completion); | |
7c673cae FG |
82 | } |
83 | ||
c07f9fc5 FG |
84 | template <typename I> |
85 | ObjectRequest<I>* | |
9f95a23c TL |
86 | ObjectRequest<I>::create_compare_and_write( |
87 | I *ictx, uint64_t object_no, uint64_t object_off, | |
88 | ceph::bufferlist&& cmp_data, ceph::bufferlist&& write_data, | |
89 | const ::SnapContext &snapc, uint64_t *mismatch_offset, int op_flags, | |
90 | const ZTracer::Trace &parent_trace, Context *completion) { | |
91 | return new ObjectCompareAndWriteRequest<I>(ictx, object_no, object_off, | |
11fdf7f2 TL |
92 | std::move(cmp_data), |
93 | std::move(write_data), snapc, | |
b32b8144 FG |
94 | mismatch_offset, op_flags, |
95 | parent_trace, completion); | |
c07f9fc5 FG |
96 | } |
97 | ||
7c673cae | 98 | template <typename I> |
9f95a23c TL |
99 | ObjectRequest<I>::ObjectRequest( |
100 | I *ictx, uint64_t objectno, uint64_t off, uint64_t len, | |
101 | librados::snap_t snap_id, const char *trace_name, | |
102 | const ZTracer::Trace &trace, Context *completion) | |
103 | : m_ictx(ictx), m_object_no(objectno), m_object_off(off), | |
7c673cae | 104 | m_object_len(len), m_snap_id(snap_id), m_completion(completion), |
31f18b77 | 105 | m_trace(util::create_trace(*ictx, "", trace)) { |
eafe8130 | 106 | ceph_assert(m_ictx->data_ctx.is_valid()); |
31f18b77 | 107 | if (m_trace.valid()) { |
9f95a23c TL |
108 | m_trace.copy_name(trace_name + std::string(" ") + |
109 | data_object_name(ictx, objectno)); | |
31f18b77 FG |
110 | m_trace.event("start"); |
111 | } | |
7c673cae FG |
112 | } |
113 | ||
114 | template <typename I> | |
b32b8144 FG |
115 | void ObjectRequest<I>::add_write_hint(I& image_ctx, |
116 | librados::ObjectWriteOperation *wr) { | |
117 | if (image_ctx.enable_alloc_hint) { | |
92f5a8d4 TL |
118 | wr->set_alloc_hint2(image_ctx.get_object_size(), |
119 | image_ctx.get_object_size(), | |
120 | image_ctx.alloc_hint_flags); | |
121 | } else if (image_ctx.alloc_hint_flags != 0U) { | |
122 | wr->set_alloc_hint2(0, 0, image_ctx.alloc_hint_flags); | |
7c673cae FG |
123 | } |
124 | } | |
125 | ||
126 | template <typename I> | |
11fdf7f2 TL |
127 | bool ObjectRequest<I>::compute_parent_extents(Extents *parent_extents, |
128 | bool read_request) { | |
9f95a23c | 129 | ceph_assert(ceph_mutex_is_locked(m_ictx->image_lock)); |
7c673cae | 130 | |
b32b8144 FG |
131 | m_has_parent = false; |
132 | parent_extents->clear(); | |
133 | ||
7c673cae FG |
134 | uint64_t parent_overlap; |
135 | int r = m_ictx->get_parent_overlap(m_snap_id, &parent_overlap); | |
136 | if (r < 0) { | |
137 | // NOTE: it's possible for a snapshot to be deleted while we are | |
138 | // still reading from it | |
139 | lderr(m_ictx->cct) << "failed to retrieve parent overlap: " | |
b32b8144 FG |
140 | << cpp_strerror(r) << dendl; |
141 | return false; | |
11fdf7f2 TL |
142 | } |
143 | ||
144 | if (!read_request && !m_ictx->migration_info.empty()) { | |
145 | parent_overlap = m_ictx->migration_info.overlap; | |
146 | } | |
147 | ||
148 | if (parent_overlap == 0) { | |
7c673cae FG |
149 | return false; |
150 | } | |
151 | ||
b32b8144 FG |
152 | Striper::extent_to_file(m_ictx->cct, &m_ictx->layout, m_object_no, 0, |
153 | m_ictx->layout.object_size, *parent_extents); | |
154 | uint64_t object_overlap = m_ictx->prune_parent_extents(*parent_extents, | |
155 | parent_overlap); | |
7c673cae FG |
156 | if (object_overlap > 0) { |
157 | ldout(m_ictx->cct, 20) << "overlap " << parent_overlap << " " | |
b32b8144 FG |
158 | << "extents " << *parent_extents << dendl; |
159 | m_has_parent = !parent_extents->empty(); | |
7c673cae FG |
160 | return true; |
161 | } | |
162 | return false; | |
163 | } | |
164 | ||
b32b8144 FG |
165 | template <typename I> |
166 | void ObjectRequest<I>::async_finish(int r) { | |
167 | ldout(m_ictx->cct, 20) << "r=" << r << dendl; | |
168 | m_ictx->op_work_queue->queue(util::create_context_callback< | |
169 | ObjectRequest<I>, &ObjectRequest<I>::finish>(this), r); | |
170 | } | |
171 | ||
172 | template <typename I> | |
173 | void ObjectRequest<I>::finish(int r) { | |
174 | ldout(m_ictx->cct, 20) << "r=" << r << dendl; | |
175 | m_completion->complete(r); | |
176 | delete this; | |
7c673cae FG |
177 | } |
178 | ||
179 | /** read **/ | |
180 | ||
181 | template <typename I> | |
9f95a23c TL |
182 | ObjectReadRequest<I>::ObjectReadRequest( |
183 | I *ictx, uint64_t objectno, uint64_t offset, uint64_t len, | |
184 | librados::snap_t snap_id, int op_flags, const ZTracer::Trace &parent_trace, | |
185 | bufferlist* read_data, ExtentMap* extent_map, Context *completion) | |
186 | : ObjectRequest<I>(ictx, objectno, offset, len, snap_id, "read", | |
b32b8144 | 187 | parent_trace, completion), |
11fdf7f2 | 188 | m_op_flags(op_flags), m_read_data(read_data), m_extent_map(extent_map) { |
7c673cae FG |
189 | } |
190 | ||
191 | template <typename I> | |
b32b8144 FG |
192 | void ObjectReadRequest<I>::send() { |
193 | I *image_ctx = this->m_ictx; | |
194 | ldout(image_ctx->cct, 20) << dendl; | |
7c673cae | 195 | |
11fdf7f2 | 196 | read_object(); |
b32b8144 FG |
197 | } |
198 | ||
199 | template <typename I> | |
200 | void ObjectReadRequest<I>::read_object() { | |
201 | I *image_ctx = this->m_ictx; | |
7c673cae | 202 | { |
9f95a23c | 203 | std::shared_lock image_locker{image_ctx->image_lock}; |
7c673cae FG |
204 | if (image_ctx->object_map != nullptr && |
205 | !image_ctx->object_map->object_may_exist(this->m_object_no)) { | |
9f95a23c | 206 | image_ctx->op_work_queue->queue(new LambdaContext([this](int r) { |
b32b8144 FG |
207 | read_parent(); |
208 | }), 0); | |
7c673cae FG |
209 | return; |
210 | } | |
211 | } | |
212 | ||
b32b8144 FG |
213 | ldout(image_ctx->cct, 20) << dendl; |
214 | ||
7c673cae | 215 | librados::ObjectReadOperation op; |
b32b8144 | 216 | if (this->m_object_len >= image_ctx->sparse_read_threshold_bytes) { |
11fdf7f2 TL |
217 | op.sparse_read(this->m_object_off, this->m_object_len, m_extent_map, |
218 | m_read_data, nullptr); | |
7c673cae | 219 | } else { |
11fdf7f2 | 220 | op.read(this->m_object_off, this->m_object_len, m_read_data, nullptr); |
7c673cae FG |
221 | } |
222 | op.set_op_flags2(m_op_flags); | |
223 | ||
b32b8144 FG |
224 | librados::AioCompletion *rados_completion = util::create_rados_callback< |
225 | ObjectReadRequest<I>, &ObjectReadRequest<I>::handle_read_object>(this); | |
226 | int flags = image_ctx->get_read_flags(this->m_snap_id); | |
31f18b77 | 227 | int r = image_ctx->data_ctx.aio_operate( |
9f95a23c TL |
228 | data_object_name(this->m_ictx, this->m_object_no), rados_completion, &op, |
229 | flags, nullptr, | |
31f18b77 | 230 | (this->m_trace.valid() ? this->m_trace.get_info() : nullptr)); |
11fdf7f2 | 231 | ceph_assert(r == 0); |
7c673cae FG |
232 | |
233 | rados_completion->release(); | |
234 | } | |
235 | ||
236 | template <typename I> | |
b32b8144 FG |
237 | void ObjectReadRequest<I>::handle_read_object(int r) { |
238 | I *image_ctx = this->m_ictx; | |
239 | ldout(image_ctx->cct, 20) << "r=" << r << dendl; | |
240 | ||
241 | if (r == -ENOENT) { | |
242 | read_parent(); | |
243 | return; | |
244 | } else if (r < 0) { | |
245 | lderr(image_ctx->cct) << "failed to read from object: " | |
246 | << cpp_strerror(r) << dendl; | |
247 | this->finish(r); | |
248 | return; | |
249 | } | |
7c673cae | 250 | |
b32b8144 FG |
251 | this->finish(0); |
252 | } | |
253 | ||
254 | template <typename I> | |
255 | void ObjectReadRequest<I>::read_parent() { | |
256 | I *image_ctx = this->m_ictx; | |
b32b8144 | 257 | |
9f95a23c | 258 | std::shared_lock image_locker{image_ctx->image_lock}; |
81eedcae TL |
259 | |
260 | // calculate reverse mapping onto the image | |
b32b8144 | 261 | Extents parent_extents; |
81eedcae TL |
262 | Striper::extent_to_file(image_ctx->cct, &image_ctx->layout, |
263 | this->m_object_no, this->m_object_off, | |
264 | this->m_object_len, parent_extents); | |
265 | ||
266 | uint64_t parent_overlap = 0; | |
267 | uint64_t object_overlap = 0; | |
268 | int r = image_ctx->get_parent_overlap(this->m_snap_id, &parent_overlap); | |
269 | if (r == 0) { | |
270 | object_overlap = image_ctx->prune_parent_extents(parent_extents, | |
271 | parent_overlap); | |
7c673cae FG |
272 | } |
273 | ||
b32b8144 | 274 | if (object_overlap == 0) { |
9f95a23c | 275 | image_locker.unlock(); |
81eedcae | 276 | |
b32b8144 FG |
277 | this->finish(-ENOENT); |
278 | return; | |
279 | } | |
280 | ||
281 | ldout(image_ctx->cct, 20) << dendl; | |
282 | ||
81eedcae | 283 | auto parent_completion = AioCompletion::create_and_start< |
b32b8144 FG |
284 | ObjectReadRequest<I>, &ObjectReadRequest<I>::handle_read_parent>( |
285 | this, util::get_image_ctx(image_ctx->parent), AIO_TYPE_READ); | |
286 | ImageRequest<I>::aio_read(image_ctx->parent, parent_completion, | |
11fdf7f2 | 287 | std::move(parent_extents), ReadResult{m_read_data}, |
b32b8144 FG |
288 | 0, this->m_trace); |
289 | } | |
290 | ||
291 | template <typename I> | |
292 | void ObjectReadRequest<I>::handle_read_parent(int r) { | |
293 | I *image_ctx = this->m_ictx; | |
294 | ldout(image_ctx->cct, 20) << "r=" << r << dendl; | |
295 | ||
296 | if (r == -ENOENT) { | |
297 | this->finish(r); | |
298 | return; | |
299 | } else if (r < 0) { | |
300 | lderr(image_ctx->cct) << "failed to read parent extents: " | |
301 | << cpp_strerror(r) << dendl; | |
302 | this->finish(r); | |
303 | return; | |
304 | } | |
305 | ||
306 | copyup(); | |
307 | } | |
308 | ||
309 | template <typename I> | |
310 | void ObjectReadRequest<I>::copyup() { | |
311 | I *image_ctx = this->m_ictx; | |
312 | if (!is_copy_on_read(image_ctx, this->m_snap_id)) { | |
313 | this->finish(0); | |
314 | return; | |
315 | } | |
316 | ||
9f95a23c TL |
317 | image_ctx->owner_lock.lock_shared(); |
318 | image_ctx->image_lock.lock_shared(); | |
b32b8144 | 319 | Extents parent_extents; |
11fdf7f2 | 320 | if (!this->compute_parent_extents(&parent_extents, true) || |
b32b8144 FG |
321 | (image_ctx->exclusive_lock != nullptr && |
322 | !image_ctx->exclusive_lock->is_lock_owner())) { | |
9f95a23c TL |
323 | image_ctx->image_lock.unlock_shared(); |
324 | image_ctx->owner_lock.unlock_shared(); | |
b32b8144 FG |
325 | this->finish(0); |
326 | return; | |
327 | } | |
328 | ||
329 | ldout(image_ctx->cct, 20) << dendl; | |
330 | ||
9f95a23c | 331 | image_ctx->copyup_list_lock.lock(); |
b32b8144 | 332 | auto it = image_ctx->copyup_list.find(this->m_object_no); |
7c673cae FG |
333 | if (it == image_ctx->copyup_list.end()) { |
334 | // create and kick off a CopyupRequest | |
b32b8144 | 335 | auto new_req = CopyupRequest<I>::create( |
9f95a23c | 336 | image_ctx, this->m_object_no, std::move(parent_extents), this->m_trace); |
7c673cae FG |
337 | |
338 | image_ctx->copyup_list[this->m_object_no] = new_req; | |
9f95a23c TL |
339 | image_ctx->copyup_list_lock.unlock(); |
340 | image_ctx->image_lock.unlock_shared(); | |
7c673cae | 341 | new_req->send(); |
11fdf7f2 | 342 | } else { |
9f95a23c TL |
343 | image_ctx->copyup_list_lock.unlock(); |
344 | image_ctx->image_lock.unlock_shared(); | |
7c673cae | 345 | } |
7c673cae | 346 | |
9f95a23c | 347 | image_ctx->owner_lock.unlock_shared(); |
b32b8144 | 348 | this->finish(0); |
7c673cae FG |
349 | } |
350 | ||
351 | /** write **/ | |
352 | ||
b32b8144 FG |
353 | template <typename I> |
354 | AbstractObjectWriteRequest<I>::AbstractObjectWriteRequest( | |
9f95a23c TL |
355 | I *ictx, uint64_t object_no, uint64_t object_off, uint64_t len, |
356 | const ::SnapContext &snapc, const char *trace_name, | |
b32b8144 | 357 | const ZTracer::Trace &parent_trace, Context *completion) |
9f95a23c TL |
358 | : ObjectRequest<I>(ictx, object_no, object_off, len, CEPH_NOSNAP, trace_name, |
359 | parent_trace, completion), | |
b32b8144 | 360 | m_snap_seq(snapc.seq.val) |
7c673cae FG |
361 | { |
362 | m_snaps.insert(m_snaps.end(), snapc.snaps.begin(), snapc.snaps.end()); | |
7c673cae | 363 | |
b32b8144 FG |
364 | if (this->m_object_off == 0 && |
365 | this->m_object_len == ictx->get_object_size()) { | |
366 | m_full_object = true; | |
367 | } | |
7c673cae | 368 | |
11fdf7f2 | 369 | compute_parent_info(); |
81eedcae | 370 | |
9f95a23c | 371 | ictx->image_lock.lock_shared(); |
81eedcae TL |
372 | if (!ictx->migration_info.empty()) { |
373 | m_guarding_migration_write = true; | |
374 | } | |
9f95a23c | 375 | ictx->image_lock.unlock_shared(); |
11fdf7f2 TL |
376 | } |
377 | ||
378 | template <typename I> | |
379 | void AbstractObjectWriteRequest<I>::compute_parent_info() { | |
380 | I *image_ctx = this->m_ictx; | |
9f95a23c | 381 | std::shared_lock image_locker{image_ctx->image_lock}; |
11fdf7f2 TL |
382 | |
383 | this->compute_parent_extents(&m_parent_extents, false); | |
384 | ||
b32b8144 FG |
385 | if (!this->has_parent() || |
386 | (m_full_object && m_snaps.empty() && !is_post_copyup_write_required())) { | |
11fdf7f2 | 387 | m_copyup_enabled = false; |
7c673cae | 388 | } |
b32b8144 | 389 | } |
7c673cae | 390 | |
b32b8144 FG |
391 | template <typename I> |
392 | void AbstractObjectWriteRequest<I>::add_write_hint( | |
393 | librados::ObjectWriteOperation *wr) { | |
394 | I *image_ctx = this->m_ictx; | |
9f95a23c | 395 | std::shared_lock image_locker{image_ctx->image_lock}; |
b32b8144 FG |
396 | if (image_ctx->object_map == nullptr || !this->m_object_may_exist) { |
397 | ObjectRequest<I>::add_write_hint(*image_ctx, wr); | |
398 | } | |
7c673cae FG |
399 | } |
400 | ||
b32b8144 FG |
401 | template <typename I> |
402 | void AbstractObjectWriteRequest<I>::send() { | |
403 | I *image_ctx = this->m_ictx; | |
9f95a23c | 404 | ldout(image_ctx->cct, 20) << this->get_op_type() << " " |
b32b8144 FG |
405 | << this->m_object_off << "~" << this->m_object_len |
406 | << dendl; | |
7c673cae | 407 | { |
9f95a23c | 408 | std::shared_lock image_lock{image_ctx->image_lock}; |
b32b8144 FG |
409 | if (image_ctx->object_map == nullptr) { |
410 | m_object_may_exist = true; | |
7c673cae FG |
411 | } else { |
412 | // should have been flushed prior to releasing lock | |
11fdf7f2 | 413 | ceph_assert(image_ctx->exclusive_lock->is_lock_owner()); |
b32b8144 FG |
414 | m_object_may_exist = image_ctx->object_map->object_may_exist( |
415 | this->m_object_no); | |
7c673cae FG |
416 | } |
417 | } | |
418 | ||
b32b8144 FG |
419 | if (!m_object_may_exist && is_no_op_for_nonexistent_object()) { |
420 | ldout(image_ctx->cct, 20) << "skipping no-op on nonexistent object" | |
421 | << dendl; | |
422 | this->async_finish(0); | |
423 | return; | |
7c673cae FG |
424 | } |
425 | ||
b32b8144 | 426 | pre_write_object_map_update(); |
7c673cae FG |
427 | } |
428 | ||
b32b8144 FG |
429 | template <typename I> |
430 | void AbstractObjectWriteRequest<I>::pre_write_object_map_update() { | |
431 | I *image_ctx = this->m_ictx; | |
7c673cae | 432 | |
9f95a23c | 433 | image_ctx->image_lock.lock_shared(); |
b32b8144 | 434 | if (image_ctx->object_map == nullptr || !is_object_map_update_enabled()) { |
9f95a23c | 435 | image_ctx->image_lock.unlock_shared(); |
b32b8144 FG |
436 | write_object(); |
437 | return; | |
7c673cae FG |
438 | } |
439 | ||
b32b8144 FG |
440 | if (!m_object_may_exist && m_copyup_enabled) { |
441 | // optimization: copyup required | |
9f95a23c | 442 | image_ctx->image_lock.unlock_shared(); |
b32b8144 FG |
443 | copyup(); |
444 | return; | |
445 | } | |
7c673cae | 446 | |
b32b8144 | 447 | uint8_t new_state = this->get_pre_write_object_map_state(); |
9f95a23c TL |
448 | ldout(image_ctx->cct, 20) << this->m_object_off << "~" << this->m_object_len |
449 | << dendl; | |
7c673cae | 450 | |
b32b8144 FG |
451 | if (image_ctx->object_map->template aio_update< |
452 | AbstractObjectWriteRequest<I>, | |
453 | &AbstractObjectWriteRequest<I>::handle_pre_write_object_map_update>( | |
91327a77 AA |
454 | CEPH_NOSNAP, this->m_object_no, new_state, {}, this->m_trace, false, |
455 | this)) { | |
9f95a23c | 456 | image_ctx->image_lock.unlock_shared(); |
b32b8144 | 457 | return; |
7c673cae FG |
458 | } |
459 | ||
9f95a23c | 460 | image_ctx->image_lock.unlock_shared(); |
b32b8144 | 461 | write_object(); |
7c673cae FG |
462 | } |
463 | ||
b32b8144 FG |
464 | template <typename I> |
465 | void AbstractObjectWriteRequest<I>::handle_pre_write_object_map_update(int r) { | |
466 | I *image_ctx = this->m_ictx; | |
467 | ldout(image_ctx->cct, 20) << "r=" << r << dendl; | |
11fdf7f2 TL |
468 | if (r < 0) { |
469 | lderr(image_ctx->cct) << "failed to update object map: " | |
470 | << cpp_strerror(r) << dendl; | |
471 | this->finish(r); | |
472 | return; | |
473 | } | |
7c673cae | 474 | |
b32b8144 | 475 | write_object(); |
7c673cae FG |
476 | } |
477 | ||
b32b8144 FG |
478 | template <typename I> |
479 | void AbstractObjectWriteRequest<I>::write_object() { | |
480 | I *image_ctx = this->m_ictx; | |
481 | ldout(image_ctx->cct, 20) << dendl; | |
7c673cae | 482 | |
b32b8144 FG |
483 | librados::ObjectWriteOperation write; |
484 | if (m_copyup_enabled) { | |
485 | ldout(image_ctx->cct, 20) << "guarding write" << dendl; | |
81eedcae | 486 | if (m_guarding_migration_write) { |
11fdf7f2 TL |
487 | cls_client::assert_snapc_seq( |
488 | &write, m_snap_seq, cls::rbd::ASSERT_SNAPC_SEQ_LE_SNAPSET_SEQ); | |
489 | } else { | |
490 | write.assert_exists(); | |
491 | } | |
7c673cae FG |
492 | } |
493 | ||
b32b8144 FG |
494 | add_write_hint(&write); |
495 | add_write_ops(&write); | |
11fdf7f2 | 496 | ceph_assert(write.size() != 0); |
7c673cae | 497 | |
b32b8144 FG |
498 | librados::AioCompletion *rados_completion = util::create_rados_callback< |
499 | AbstractObjectWriteRequest<I>, | |
500 | &AbstractObjectWriteRequest<I>::handle_write_object>(this); | |
501 | int r = image_ctx->data_ctx.aio_operate( | |
9f95a23c TL |
502 | data_object_name(this->m_ictx, this->m_object_no), rados_completion, |
503 | &write, m_snap_seq, m_snaps, | |
31f18b77 | 504 | (this->m_trace.valid() ? this->m_trace.get_info() : nullptr)); |
11fdf7f2 | 505 | ceph_assert(r == 0); |
7c673cae FG |
506 | rados_completion->release(); |
507 | } | |
7c673cae | 508 | |
b32b8144 FG |
509 | template <typename I> |
510 | void AbstractObjectWriteRequest<I>::handle_write_object(int r) { | |
511 | I *image_ctx = this->m_ictx; | |
512 | ldout(image_ctx->cct, 20) << "r=" << r << dendl; | |
513 | ||
514 | r = filter_write_result(r); | |
515 | if (r == -ENOENT) { | |
516 | if (m_copyup_enabled) { | |
517 | copyup(); | |
518 | return; | |
519 | } | |
11fdf7f2 | 520 | } else if (r == -ERANGE && m_guarding_migration_write) { |
9f95a23c | 521 | image_ctx->image_lock.lock_shared(); |
81eedcae | 522 | m_guarding_migration_write = !image_ctx->migration_info.empty(); |
9f95a23c | 523 | image_ctx->image_lock.unlock_shared(); |
81eedcae TL |
524 | |
525 | if (m_guarding_migration_write) { | |
11fdf7f2 TL |
526 | copyup(); |
527 | } else { | |
528 | ldout(image_ctx->cct, 10) << "migration parent gone, restart io" << dendl; | |
11fdf7f2 TL |
529 | compute_parent_info(); |
530 | write_object(); | |
531 | } | |
532 | return; | |
b32b8144 FG |
533 | } else if (r == -EILSEQ) { |
534 | ldout(image_ctx->cct, 10) << "failed to write object" << dendl; | |
535 | this->finish(r); | |
536 | return; | |
537 | } else if (r < 0) { | |
538 | lderr(image_ctx->cct) << "failed to write object: " << cpp_strerror(r) | |
539 | << dendl; | |
540 | this->finish(r); | |
541 | return; | |
7c673cae FG |
542 | } |
543 | ||
b32b8144 | 544 | post_write_object_map_update(); |
7c673cae FG |
545 | } |
546 | ||
b32b8144 FG |
547 | template <typename I> |
548 | void AbstractObjectWriteRequest<I>::copyup() { | |
549 | I *image_ctx = this->m_ictx; | |
550 | ldout(image_ctx->cct, 20) << dendl; | |
7c673cae | 551 | |
11fdf7f2 | 552 | ceph_assert(!m_copyup_in_progress); |
b32b8144 | 553 | m_copyup_in_progress = true; |
7c673cae | 554 | |
9f95a23c | 555 | image_ctx->copyup_list_lock.lock(); |
b32b8144 FG |
556 | auto it = image_ctx->copyup_list.find(this->m_object_no); |
557 | if (it == image_ctx->copyup_list.end()) { | |
558 | auto new_req = CopyupRequest<I>::create( | |
9f95a23c TL |
559 | image_ctx, this->m_object_no, std::move(this->m_parent_extents), |
560 | this->m_trace); | |
b32b8144 FG |
561 | this->m_parent_extents.clear(); |
562 | ||
563 | // make sure to wait on this CopyupRequest | |
564 | new_req->append_request(this); | |
565 | image_ctx->copyup_list[this->m_object_no] = new_req; | |
566 | ||
9f95a23c | 567 | image_ctx->copyup_list_lock.unlock(); |
b32b8144 | 568 | new_req->send(); |
31f18b77 | 569 | } else { |
b32b8144 | 570 | it->second->append_request(this); |
9f95a23c | 571 | image_ctx->copyup_list_lock.unlock(); |
31f18b77 | 572 | } |
7c673cae FG |
573 | } |
574 | ||
b32b8144 FG |
575 | template <typename I> |
576 | void AbstractObjectWriteRequest<I>::handle_copyup(int r) { | |
577 | I *image_ctx = this->m_ictx; | |
578 | ldout(image_ctx->cct, 20) << "r=" << r << dendl; | |
579 | ||
11fdf7f2 | 580 | ceph_assert(m_copyup_in_progress); |
b32b8144 FG |
581 | m_copyup_in_progress = false; |
582 | ||
81eedcae | 583 | if (r < 0 && r != -ERESTART) { |
b32b8144 FG |
584 | lderr(image_ctx->cct) << "failed to copyup object: " << cpp_strerror(r) |
585 | << dendl; | |
586 | this->finish(r); | |
587 | return; | |
31f18b77 | 588 | } |
31f18b77 | 589 | |
81eedcae | 590 | if (r == -ERESTART || is_post_copyup_write_required()) { |
b32b8144 FG |
591 | write_object(); |
592 | return; | |
7c673cae | 593 | } |
b32b8144 FG |
594 | |
595 | post_write_object_map_update(); | |
7c673cae FG |
596 | } |
597 | ||
b32b8144 FG |
598 | template <typename I> |
599 | void AbstractObjectWriteRequest<I>::post_write_object_map_update() { | |
600 | I *image_ctx = this->m_ictx; | |
601 | ||
9f95a23c | 602 | image_ctx->image_lock.lock_shared(); |
b32b8144 FG |
603 | if (image_ctx->object_map == nullptr || !is_object_map_update_enabled() || |
604 | !is_non_existent_post_write_object_map_state()) { | |
9f95a23c | 605 | image_ctx->image_lock.unlock_shared(); |
b32b8144 FG |
606 | this->finish(0); |
607 | return; | |
7c673cae FG |
608 | } |
609 | ||
b32b8144 | 610 | ldout(image_ctx->cct, 20) << dendl; |
7c673cae | 611 | |
b32b8144 | 612 | // should have been flushed prior to releasing lock |
11fdf7f2 | 613 | ceph_assert(image_ctx->exclusive_lock->is_lock_owner()); |
b32b8144 FG |
614 | if (image_ctx->object_map->template aio_update< |
615 | AbstractObjectWriteRequest<I>, | |
616 | &AbstractObjectWriteRequest<I>::handle_post_write_object_map_update>( | |
617 | CEPH_NOSNAP, this->m_object_no, OBJECT_NONEXISTENT, OBJECT_PENDING, | |
91327a77 | 618 | this->m_trace, false, this)) { |
9f95a23c | 619 | image_ctx->image_lock.unlock_shared(); |
b32b8144 | 620 | return; |
7c673cae FG |
621 | } |
622 | ||
9f95a23c | 623 | image_ctx->image_lock.unlock_shared(); |
b32b8144 | 624 | this->finish(0); |
7c673cae FG |
625 | } |
626 | ||
b32b8144 FG |
627 | template <typename I> |
628 | void AbstractObjectWriteRequest<I>::handle_post_write_object_map_update(int r) { | |
629 | I *image_ctx = this->m_ictx; | |
630 | ldout(image_ctx->cct, 20) << "r=" << r << dendl; | |
11fdf7f2 TL |
631 | if (r < 0) { |
632 | lderr(image_ctx->cct) << "failed to update object map: " | |
633 | << cpp_strerror(r) << dendl; | |
634 | this->finish(r); | |
635 | return; | |
636 | } | |
c07f9fc5 | 637 | |
b32b8144 FG |
638 | this->finish(0); |
639 | } | |
c07f9fc5 | 640 | |
b32b8144 FG |
641 | template <typename I> |
642 | void ObjectWriteRequest<I>::add_write_ops(librados::ObjectWriteOperation *wr) { | |
643 | if (this->m_full_object) { | |
644 | wr->write_full(m_write_data); | |
c07f9fc5 | 645 | } else { |
b32b8144 | 646 | wr->write(this->m_object_off, m_write_data); |
c07f9fc5 FG |
647 | } |
648 | wr->set_op_flags2(m_op_flags); | |
649 | } | |
650 | ||
b32b8144 FG |
651 | template <typename I> |
652 | void ObjectWriteSameRequest<I>::add_write_ops( | |
653 | librados::ObjectWriteOperation *wr) { | |
654 | wr->writesame(this->m_object_off, this->m_object_len, m_write_data); | |
655 | wr->set_op_flags2(m_op_flags); | |
c07f9fc5 FG |
656 | } |
657 | ||
b32b8144 FG |
658 | template <typename I> |
659 | void ObjectCompareAndWriteRequest<I>::add_write_ops( | |
660 | librados::ObjectWriteOperation *wr) { | |
661 | wr->cmpext(this->m_object_off, m_cmp_bl, nullptr); | |
c07f9fc5 | 662 | |
b32b8144 FG |
663 | if (this->m_full_object) { |
664 | wr->write_full(m_write_bl); | |
665 | } else { | |
666 | wr->write(this->m_object_off, m_write_bl); | |
667 | } | |
668 | wr->set_op_flags2(m_op_flags); | |
669 | } | |
c07f9fc5 | 670 | |
b32b8144 FG |
671 | template <typename I> |
672 | int ObjectCompareAndWriteRequest<I>::filter_write_result(int r) const { | |
673 | if (r <= -MAX_ERRNO) { | |
674 | I *image_ctx = this->m_ictx; | |
675 | Extents image_extents; | |
676 | ||
677 | // object extent compare mismatch | |
678 | uint64_t offset = -MAX_ERRNO - r; | |
679 | Striper::extent_to_file(image_ctx->cct, &image_ctx->layout, | |
680 | this->m_object_no, offset, this->m_object_len, | |
681 | image_extents); | |
11fdf7f2 | 682 | ceph_assert(image_extents.size() == 1); |
b32b8144 FG |
683 | |
684 | if (m_mismatch_offset) { | |
685 | *m_mismatch_offset = image_extents[0].first; | |
c07f9fc5 | 686 | } |
b32b8144 | 687 | r = -EILSEQ; |
c07f9fc5 | 688 | } |
b32b8144 | 689 | return r; |
c07f9fc5 FG |
690 | } |
691 | ||
7c673cae FG |
692 | } // namespace io |
693 | } // namespace librbd | |
694 | ||
695 | template class librbd::io::ObjectRequest<librbd::ImageCtx>; | |
696 | template class librbd::io::ObjectReadRequest<librbd::ImageCtx>; | |
b32b8144 FG |
697 | template class librbd::io::AbstractObjectWriteRequest<librbd::ImageCtx>; |
698 | template class librbd::io::ObjectWriteRequest<librbd::ImageCtx>; | |
699 | template class librbd::io::ObjectDiscardRequest<librbd::ImageCtx>; | |
700 | template class librbd::io::ObjectWriteSameRequest<librbd::ImageCtx>; | |
701 | template class librbd::io::ObjectCompareAndWriteRequest<librbd::ImageCtx>; |