]> git.proxmox.com Git - ceph.git/blame - ceph/src/librbd/io/ImageRequest.cc
update sources to v12.2.3
[ceph.git] / ceph / src / librbd / io / ImageRequest.cc
CommitLineData
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/ImageRequest.h"
5#include "librbd/ImageCtx.h"
6#include "librbd/internal.h"
7#include "librbd/Journal.h"
b32b8144 8#include "librbd/Types.h"
7c673cae
FG
9#include "librbd/Utils.h"
10#include "librbd/cache/ImageCache.h"
11#include "librbd/io/AioCompletion.h"
12#include "librbd/io/ObjectRequest.h"
13#include "librbd/journal/Types.h"
14#include "include/rados/librados.hpp"
15#include "common/WorkQueue.h"
16#include "osdc/Striper.h"
17
18#define dout_subsys ceph_subsys_rbd
19#undef dout_prefix
20#define dout_prefix *_dout << "librbd::io::ImageRequest: " << this \
21 << " " << __func__ << ": "
22
23namespace librbd {
24namespace io {
25
26using util::get_image_ctx;
27
28namespace {
29
30template <typename ImageCtxT = ImageCtx>
31struct C_DiscardJournalCommit : public Context {
32 typedef std::vector<ObjectExtent> ObjectExtents;
33
34 ImageCtxT &image_ctx;
35 AioCompletion *aio_comp;
36 ObjectExtents object_extents;
37
38 C_DiscardJournalCommit(ImageCtxT &_image_ctx, AioCompletion *_aio_comp,
39 const ObjectExtents &_object_extents, uint64_t tid)
40 : image_ctx(_image_ctx), aio_comp(_aio_comp),
41 object_extents(_object_extents) {
42 CephContext *cct = image_ctx.cct;
43 ldout(cct, 20) << "delaying cache discard until journal tid " << tid << " "
44 << "safe" << dendl;
45
46 aio_comp->add_request();
47 }
48
49 void finish(int r) override {
50 CephContext *cct = image_ctx.cct;
51 ldout(cct, 20) << "C_DiscardJournalCommit: "
52 << "journal committed: discarding from cache" << dendl;
53
54 Mutex::Locker cache_locker(image_ctx.cache_lock);
55 image_ctx.object_cacher->discard_set(image_ctx.object_set, object_extents);
56 aio_comp->complete_request(r);
57 }
58};
59
60template <typename ImageCtxT = ImageCtx>
61struct C_FlushJournalCommit : public Context {
62 ImageCtxT &image_ctx;
63 AioCompletion *aio_comp;
64
65 C_FlushJournalCommit(ImageCtxT &_image_ctx, AioCompletion *_aio_comp,
66 uint64_t tid)
67 : image_ctx(_image_ctx), aio_comp(_aio_comp) {
68 CephContext *cct = image_ctx.cct;
69 ldout(cct, 20) << "delaying flush until journal tid " << tid << " "
70 << "safe" << dendl;
71
72 aio_comp->add_request();
73 }
74
75 void finish(int r) override {
76 CephContext *cct = image_ctx.cct;
77 ldout(cct, 20) << "C_FlushJournalCommit: journal committed" << dendl;
78 aio_comp->complete_request(r);
79 }
80};
81
7c673cae
FG
82} // anonymous namespace
83
224ce89b
WB
84template <typename I>
85ImageRequest<I>* ImageRequest<I>::create_read_request(
86 I &image_ctx, AioCompletion *aio_comp, Extents &&image_extents,
87 ReadResult &&read_result, int op_flags,
88 const ZTracer::Trace &parent_trace) {
89 return new ImageReadRequest<I>(image_ctx, aio_comp,
90 std::move(image_extents),
91 std::move(read_result), op_flags,
92 parent_trace);
93}
94
95template <typename I>
96ImageRequest<I>* ImageRequest<I>::create_write_request(
97 I &image_ctx, AioCompletion *aio_comp, Extents &&image_extents,
98 bufferlist &&bl, int op_flags, const ZTracer::Trace &parent_trace) {
99 return new ImageWriteRequest<I>(image_ctx, aio_comp, std::move(image_extents),
100 std::move(bl), op_flags, parent_trace);
101}
102
103template <typename I>
104ImageRequest<I>* ImageRequest<I>::create_discard_request(
105 I &image_ctx, AioCompletion *aio_comp, uint64_t off, uint64_t len,
106 bool skip_partial_discard, const ZTracer::Trace &parent_trace) {
107 return new ImageDiscardRequest<I>(image_ctx, aio_comp, off, len,
108 skip_partial_discard, parent_trace);
109}
110
111template <typename I>
112ImageRequest<I>* ImageRequest<I>::create_flush_request(
113 I &image_ctx, AioCompletion *aio_comp,
114 const ZTracer::Trace &parent_trace) {
115 return new ImageFlushRequest<I>(image_ctx, aio_comp, parent_trace);
116}
117
118template <typename I>
119ImageRequest<I>* ImageRequest<I>::create_writesame_request(
120 I &image_ctx, AioCompletion *aio_comp, uint64_t off, uint64_t len,
121 bufferlist &&bl, int op_flags, const ZTracer::Trace &parent_trace) {
122 return new ImageWriteSameRequest<I>(image_ctx, aio_comp, off, len,
123 std::move(bl), op_flags, parent_trace);
124}
125
c07f9fc5
FG
126template <typename I>
127ImageRequest<I>* ImageRequest<I>::create_compare_and_write_request(
128 I &image_ctx, AioCompletion *c, Extents &&image_extents,
129 bufferlist &&cmp_bl, bufferlist &&bl, uint64_t *mismatch_offset,
130 int op_flags, const ZTracer::Trace &parent_trace) {
131 return new ImageCompareAndWriteRequest<I>(image_ctx, c,
132 std::move(image_extents),
133 std::move(cmp_bl),
134 std::move(bl), mismatch_offset,
135 op_flags, parent_trace);
136}
137
7c673cae
FG
138template <typename I>
139void ImageRequest<I>::aio_read(I *ictx, AioCompletion *c,
140 Extents &&image_extents,
31f18b77
FG
141 ReadResult &&read_result, int op_flags,
142 const ZTracer::Trace &parent_trace) {
7c673cae 143 ImageReadRequest<I> req(*ictx, c, std::move(image_extents),
31f18b77 144 std::move(read_result), op_flags, parent_trace);
7c673cae
FG
145 req.send();
146}
147
148template <typename I>
149void ImageRequest<I>::aio_write(I *ictx, AioCompletion *c,
150 Extents &&image_extents, bufferlist &&bl,
31f18b77
FG
151 int op_flags,
152 const ZTracer::Trace &parent_trace) {
7c673cae 153 ImageWriteRequest<I> req(*ictx, c, std::move(image_extents), std::move(bl),
31f18b77 154 op_flags, parent_trace);
7c673cae
FG
155 req.send();
156}
157
158template <typename I>
159void ImageRequest<I>::aio_discard(I *ictx, AioCompletion *c,
160 uint64_t off, uint64_t len,
31f18b77
FG
161 bool skip_partial_discard,
162 const ZTracer::Trace &parent_trace) {
163 ImageDiscardRequest<I> req(*ictx, c, off, len, skip_partial_discard,
164 parent_trace);
7c673cae
FG
165 req.send();
166}
167
168template <typename I>
31f18b77
FG
169void ImageRequest<I>::aio_flush(I *ictx, AioCompletion *c,
170 const ZTracer::Trace &parent_trace) {
171 ImageFlushRequest<I> req(*ictx, c, parent_trace);
7c673cae
FG
172 req.send();
173}
174
175template <typename I>
176void ImageRequest<I>::aio_writesame(I *ictx, AioCompletion *c,
177 uint64_t off, uint64_t len,
31f18b77
FG
178 bufferlist &&bl, int op_flags,
179 const ZTracer::Trace &parent_trace) {
180 ImageWriteSameRequest<I> req(*ictx, c, off, len, std::move(bl), op_flags,
181 parent_trace);
7c673cae
FG
182 req.send();
183}
184
c07f9fc5
FG
185template <typename I>
186void ImageRequest<I>::aio_compare_and_write(I *ictx, AioCompletion *c,
187 Extents &&image_extents,
188 bufferlist &&cmp_bl,
189 bufferlist &&bl,
190 uint64_t *mismatch_offset,
191 int op_flags,
192 const ZTracer::Trace &parent_trace) {
193 ImageCompareAndWriteRequest<I> req(*ictx, c, std::move(image_extents),
194 std::move(cmp_bl), std::move(bl),
195 mismatch_offset, op_flags, parent_trace);
196 req.send();
197}
198
199
7c673cae
FG
200template <typename I>
201void ImageRequest<I>::send() {
202 I &image_ctx = this->m_image_ctx;
203 assert(m_aio_comp->is_initialized(get_aio_type()));
204 assert(m_aio_comp->is_started() ^ (get_aio_type() == AIO_TYPE_FLUSH));
205
206 CephContext *cct = image_ctx.cct;
207 AioCompletion *aio_comp = this->m_aio_comp;
208 ldout(cct, 20) << get_request_type() << ": ictx=" << &image_ctx << ", "
c07f9fc5 209 << "completion=" << aio_comp << dendl;
7c673cae
FG
210
211 aio_comp->get();
212 int r = clip_request();
213 if (r < 0) {
214 m_aio_comp->fail(r);
215 return;
216 }
217
218 if (m_bypass_image_cache || m_image_ctx.image_cache == nullptr) {
219 send_request();
220 } else {
221 send_image_cache_request();
222 }
223}
224
225template <typename I>
226int ImageRequest<I>::clip_request() {
227 RWLock::RLocker snap_locker(m_image_ctx.snap_lock);
228 for (auto &image_extent : m_image_extents) {
229 auto clip_len = image_extent.second;
230 int r = clip_io(get_image_ctx(&m_image_ctx), image_extent.first, &clip_len);
231 if (r < 0) {
232 return r;
233 }
234
235 image_extent.second = clip_len;
236 }
237 return 0;
238}
239
240template <typename I>
241void ImageRequest<I>::start_op() {
242 m_aio_comp->start_op();
243}
244
245template <typename I>
246void ImageRequest<I>::fail(int r) {
247 AioCompletion *aio_comp = this->m_aio_comp;
248 aio_comp->get();
249 aio_comp->fail(r);
250}
251
252template <typename I>
253ImageReadRequest<I>::ImageReadRequest(I &image_ctx, AioCompletion *aio_comp,
254 Extents &&image_extents,
31f18b77
FG
255 ReadResult &&read_result, int op_flags,
256 const ZTracer::Trace &parent_trace)
257 : ImageRequest<I>(image_ctx, aio_comp, std::move(image_extents), "read",
258 parent_trace),
7c673cae
FG
259 m_op_flags(op_flags) {
260 aio_comp->read_result = std::move(read_result);
261}
262
263template <typename I>
264int ImageReadRequest<I>::clip_request() {
265 int r = ImageRequest<I>::clip_request();
266 if (r < 0) {
267 return r;
268 }
269
270 uint64_t buffer_length = 0;
271 auto &image_extents = this->m_image_extents;
272 for (auto &image_extent : image_extents) {
273 buffer_length += image_extent.second;
274 }
275 this->m_aio_comp->read_result.set_clip_length(buffer_length);
276 return 0;
277}
278
279template <typename I>
280void ImageReadRequest<I>::send_request() {
281 I &image_ctx = this->m_image_ctx;
282 CephContext *cct = image_ctx.cct;
283
284 auto &image_extents = this->m_image_extents;
285 if (image_ctx.object_cacher && image_ctx.readahead_max_bytes > 0 &&
286 !(m_op_flags & LIBRADOS_OP_FLAG_FADVISE_RANDOM)) {
287 readahead(get_image_ctx(&image_ctx), image_extents);
288 }
289
290 AioCompletion *aio_comp = this->m_aio_comp;
291 librados::snap_t snap_id;
292 map<object_t,vector<ObjectExtent> > object_extents;
293 uint64_t buffer_ofs = 0;
294 {
295 // prevent image size from changing between computing clip and recording
296 // pending async operation
297 RWLock::RLocker snap_locker(image_ctx.snap_lock);
298 snap_id = image_ctx.snap_id;
299
300 // map image extents to object extents
301 for (auto &extent : image_extents) {
302 if (extent.second == 0) {
303 continue;
304 }
305
306 Striper::file_to_extents(cct, image_ctx.format_string, &image_ctx.layout,
307 extent.first, extent.second, 0, object_extents,
308 buffer_ofs);
309 buffer_ofs += extent.second;
310 }
311 }
312
313 // pre-calculate the expected number of read requests
314 uint32_t request_count = 0;
315 for (auto &object_extent : object_extents) {
316 request_count += object_extent.second.size();
317 }
318 aio_comp->set_request_count(request_count);
319
320 // issue the requests
321 for (auto &object_extent : object_extents) {
322 for (auto &extent : object_extent.second) {
323 ldout(cct, 20) << "oid " << extent.oid << " " << extent.offset << "~"
324 << extent.length << " from " << extent.buffer_extents
325 << dendl;
326
327 auto req_comp = new io::ReadResult::C_SparseReadRequest<I>(
b32b8144 328 aio_comp, std::move(extent.buffer_extents), true);
7c673cae
FG
329 ObjectReadRequest<I> *req = ObjectReadRequest<I>::create(
330 &image_ctx, extent.oid.name, extent.objectno, extent.offset,
b32b8144 331 extent.length, snap_id, m_op_flags, false, this->m_trace, req_comp);
7c673cae 332 req_comp->request = req;
b32b8144 333 req->send();
7c673cae
FG
334 }
335 }
336
337 aio_comp->put();
338
339 image_ctx.perfcounter->inc(l_librbd_rd);
340 image_ctx.perfcounter->inc(l_librbd_rd_bytes, buffer_ofs);
341}
342
343template <typename I>
344void ImageReadRequest<I>::send_image_cache_request() {
345 I &image_ctx = this->m_image_ctx;
346 assert(image_ctx.image_cache != nullptr);
347
348 AioCompletion *aio_comp = this->m_aio_comp;
349 aio_comp->set_request_count(1);
350
351 auto *req_comp = new io::ReadResult::C_ImageReadRequest(
352 aio_comp, this->m_image_extents);
353 image_ctx.image_cache->aio_read(std::move(this->m_image_extents),
354 &req_comp->bl, m_op_flags,
355 req_comp);
356}
357
358template <typename I>
359void AbstractImageWriteRequest<I>::send_request() {
360 I &image_ctx = this->m_image_ctx;
361 CephContext *cct = image_ctx.cct;
362
363 RWLock::RLocker md_locker(image_ctx.md_lock);
364
365 bool journaling = false;
366
367 AioCompletion *aio_comp = this->m_aio_comp;
368 uint64_t clip_len = 0;
369 ObjectExtents object_extents;
370 ::SnapContext snapc;
371 {
372 // prevent image size from changing between computing clip and recording
373 // pending async operation
374 RWLock::RLocker snap_locker(image_ctx.snap_lock);
375 if (image_ctx.snap_id != CEPH_NOSNAP || image_ctx.read_only) {
376 aio_comp->fail(-EROFS);
377 return;
378 }
379
380 for (auto &extent : this->m_image_extents) {
381 if (extent.second == 0) {
382 continue;
383 }
384
385 // map to object extents
386 Striper::file_to_extents(cct, image_ctx.format_string, &image_ctx.layout,
387 extent.first, extent.second, 0, object_extents);
388 clip_len += extent.second;
389 }
390
391 snapc = image_ctx.snapc;
392 journaling = (image_ctx.journal != nullptr &&
393 image_ctx.journal->is_journal_appending());
394 }
395
c07f9fc5
FG
396 int ret = prune_object_extents(object_extents);
397 if (ret < 0) {
398 aio_comp->fail(ret);
399 return;
400 }
7c673cae
FG
401
402 if (!object_extents.empty()) {
403 uint64_t journal_tid = 0;
404 aio_comp->set_request_count(
405 object_extents.size() + get_object_cache_request_count(journaling));
406
407 ObjectRequests requests;
408 send_object_requests(object_extents, snapc,
409 (journaling ? &requests : nullptr));
410
411 if (journaling) {
412 // in-flight ops are flushed prior to closing the journal
413 assert(image_ctx.journal != NULL);
414 journal_tid = append_journal_event(requests, m_synchronous);
415 }
416
417 if (image_ctx.object_cacher != NULL) {
418 send_object_cache_requests(object_extents, journal_tid);
419 }
420 } else {
421 // no IO to perform -- fire completion
422 aio_comp->unblock();
423 }
424
425 update_stats(clip_len);
426 aio_comp->put();
427}
428
429template <typename I>
430void AbstractImageWriteRequest<I>::send_object_requests(
431 const ObjectExtents &object_extents, const ::SnapContext &snapc,
432 ObjectRequests *object_requests) {
433 I &image_ctx = this->m_image_ctx;
434 CephContext *cct = image_ctx.cct;
435
436 AioCompletion *aio_comp = this->m_aio_comp;
437 for (ObjectExtents::const_iterator p = object_extents.begin();
438 p != object_extents.end(); ++p) {
439 ldout(cct, 20) << "oid " << p->oid << " " << p->offset << "~" << p->length
440 << " from " << p->buffer_extents << dendl;
441 C_AioRequest *req_comp = new C_AioRequest(aio_comp);
442 ObjectRequestHandle *request = create_object_request(*p, snapc,
443 req_comp);
444
445 // if journaling, stash the request for later; otherwise send
446 if (request != NULL) {
447 if (object_requests != NULL) {
448 object_requests->push_back(request);
449 } else {
450 request->send();
451 }
452 }
453 }
454}
455
456template <typename I>
457void ImageWriteRequest<I>::assemble_extent(const ObjectExtent &object_extent,
458 bufferlist *bl) {
459 for (auto q = object_extent.buffer_extents.begin();
460 q != object_extent.buffer_extents.end(); ++q) {
461 bufferlist sub_bl;
462 sub_bl.substr_of(m_bl, q->first, q->second);
463 bl->claim_append(sub_bl);
464 }
465}
466
467template <typename I>
468uint64_t ImageWriteRequest<I>::append_journal_event(
469 const ObjectRequests &requests, bool synchronous) {
470 I &image_ctx = this->m_image_ctx;
471
472 uint64_t tid = 0;
473 uint64_t buffer_offset = 0;
474 assert(!this->m_image_extents.empty());
475 for (auto &extent : this->m_image_extents) {
476 bufferlist sub_bl;
477 sub_bl.substr_of(m_bl, buffer_offset, extent.second);
478 buffer_offset += extent.second;
479
480 tid = image_ctx.journal->append_write_event(extent.first, extent.second,
481 sub_bl, requests, synchronous);
482 }
483
484 if (image_ctx.object_cacher == NULL) {
485 AioCompletion *aio_comp = this->m_aio_comp;
486 aio_comp->associate_journal_event(tid);
487 }
488 return tid;
489}
490
491template <typename I>
492void ImageWriteRequest<I>::send_image_cache_request() {
493 I &image_ctx = this->m_image_ctx;
494 assert(image_ctx.image_cache != nullptr);
495
496 AioCompletion *aio_comp = this->m_aio_comp;
497 aio_comp->set_request_count(1);
498 C_AioRequest *req_comp = new C_AioRequest(aio_comp);
499 image_ctx.image_cache->aio_write(std::move(this->m_image_extents),
500 std::move(m_bl), m_op_flags, req_comp);
501}
502
503template <typename I>
504void ImageWriteRequest<I>::send_object_cache_requests(
505 const ObjectExtents &object_extents, uint64_t journal_tid) {
506 I &image_ctx = this->m_image_ctx;
507 for (auto p = object_extents.begin(); p != object_extents.end(); ++p) {
508 const ObjectExtent &object_extent = *p;
509
510 bufferlist bl;
511 assemble_extent(object_extent, &bl);
512
513 AioCompletion *aio_comp = this->m_aio_comp;
514 C_AioRequest *req_comp = new C_AioRequest(aio_comp);
31f18b77
FG
515 image_ctx.write_to_cache(
516 object_extent.oid, bl, object_extent.length, object_extent.offset,
517 req_comp, m_op_flags, journal_tid,
518 (this->m_trace.valid() ? &this->m_trace : nullptr));
7c673cae
FG
519 }
520}
521
522template <typename I>
523void ImageWriteRequest<I>::send_object_requests(
524 const ObjectExtents &object_extents, const ::SnapContext &snapc,
525 ObjectRequests *object_requests) {
526 I &image_ctx = this->m_image_ctx;
527
528 // cache handles creating object requests during writeback
529 if (image_ctx.object_cacher == NULL) {
530 AbstractImageWriteRequest<I>::send_object_requests(object_extents, snapc,
531 object_requests);
532 }
533}
534
535template <typename I>
536ObjectRequestHandle *ImageWriteRequest<I>::create_object_request(
537 const ObjectExtent &object_extent, const ::SnapContext &snapc,
538 Context *on_finish) {
539 I &image_ctx = this->m_image_ctx;
540 assert(image_ctx.object_cacher == NULL);
541
542 bufferlist bl;
543 assemble_extent(object_extent, &bl);
544 ObjectRequest<I> *req = ObjectRequest<I>::create_write(
545 &image_ctx, object_extent.oid.name, object_extent.objectno,
31f18b77 546 object_extent.offset, bl, snapc, m_op_flags, this->m_trace, on_finish);
7c673cae
FG
547 return req;
548}
549
550template <typename I>
551void ImageWriteRequest<I>::update_stats(size_t length) {
552 I &image_ctx = this->m_image_ctx;
553 image_ctx.perfcounter->inc(l_librbd_wr);
554 image_ctx.perfcounter->inc(l_librbd_wr_bytes, length);
555}
556
557template <typename I>
558uint64_t ImageDiscardRequest<I>::append_journal_event(
559 const ObjectRequests &requests, bool synchronous) {
560 I &image_ctx = this->m_image_ctx;
561
562 uint64_t tid = 0;
563 assert(!this->m_image_extents.empty());
564 for (auto &extent : this->m_image_extents) {
565 journal::EventEntry event_entry(journal::AioDiscardEvent(extent.first,
566 extent.second,
567 this->m_skip_partial_discard));
568 tid = image_ctx.journal->append_io_event(std::move(event_entry),
569 requests, extent.first,
b32b8144 570 extent.second, synchronous, 0);
7c673cae
FG
571 }
572
573 AioCompletion *aio_comp = this->m_aio_comp;
574 aio_comp->associate_journal_event(tid);
575 return tid;
576}
577
578template <typename I>
c07f9fc5 579int ImageDiscardRequest<I>::prune_object_extents(ObjectExtents &object_extents) {
7c673cae
FG
580 I &image_ctx = this->m_image_ctx;
581 CephContext *cct = image_ctx.cct;
582 if (!this->m_skip_partial_discard) {
c07f9fc5 583 return 0;
7c673cae
FG
584 }
585
586 for (auto p = object_extents.begin(); p != object_extents.end(); ) {
587 if (p->offset + p->length < image_ctx.layout.object_size) {
588 ldout(cct, 20) << "oid " << p->oid << " " << p->offset << "~"
589 << p->length << " from " << p->buffer_extents
590 << ": skip partial discard" << dendl;
591 p = object_extents.erase(p);
592 } else {
593 ++p;
594 }
595 }
c07f9fc5
FG
596
597 return 0;
7c673cae
FG
598}
599
600template <typename I>
601uint32_t ImageDiscardRequest<I>::get_object_cache_request_count(bool journaling) const {
602 // extra completion request is required for tracking journal commit
603 I &image_ctx = this->m_image_ctx;
604 return (image_ctx.object_cacher != nullptr && journaling ? 1 : 0);
605}
606
607template <typename I>
608void ImageDiscardRequest<I>::send_image_cache_request() {
609 I &image_ctx = this->m_image_ctx;
610 assert(image_ctx.image_cache != nullptr);
611
612 AioCompletion *aio_comp = this->m_aio_comp;
613 aio_comp->set_request_count(this->m_image_extents.size());
614 for (auto &extent : this->m_image_extents) {
615 C_AioRequest *req_comp = new C_AioRequest(aio_comp);
616 image_ctx.image_cache->aio_discard(extent.first, extent.second,
617 this->m_skip_partial_discard, req_comp);
618 }
619}
620
621template <typename I>
622void ImageDiscardRequest<I>::send_object_cache_requests(
623 const ObjectExtents &object_extents, uint64_t journal_tid) {
624 I &image_ctx = this->m_image_ctx;
625 if (journal_tid == 0) {
626 Mutex::Locker cache_locker(image_ctx.cache_lock);
627 image_ctx.object_cacher->discard_set(image_ctx.object_set,
628 object_extents);
629 } else {
630 // cannot discard from cache until journal has committed
631 assert(image_ctx.journal != NULL);
632 AioCompletion *aio_comp = this->m_aio_comp;
633 image_ctx.journal->wait_event(
634 journal_tid, new C_DiscardJournalCommit<I>(image_ctx, aio_comp,
635 object_extents, journal_tid));
636 }
637}
638
639template <typename I>
640ObjectRequestHandle *ImageDiscardRequest<I>::create_object_request(
641 const ObjectExtent &object_extent, const ::SnapContext &snapc,
642 Context *on_finish) {
643 I &image_ctx = this->m_image_ctx;
644
b32b8144
FG
645 auto req = ObjectRequest<I>::create_discard(
646 &image_ctx, object_extent.oid.name, object_extent.objectno,
647 object_extent.offset, object_extent.length, snapc, true, true,
648 this->m_trace, on_finish);
7c673cae
FG
649 return req;
650}
651
652template <typename I>
653void ImageDiscardRequest<I>::update_stats(size_t length) {
654 I &image_ctx = this->m_image_ctx;
655 image_ctx.perfcounter->inc(l_librbd_discard);
656 image_ctx.perfcounter->inc(l_librbd_discard_bytes, length);
657}
658
659template <typename I>
660void ImageFlushRequest<I>::send_request() {
661 I &image_ctx = this->m_image_ctx;
662 image_ctx.user_flushed();
663
664 bool journaling = false;
665 {
666 RWLock::RLocker snap_locker(image_ctx.snap_lock);
667 journaling = (image_ctx.journal != nullptr &&
668 image_ctx.journal->is_journal_appending());
669 }
670
671 AioCompletion *aio_comp = this->m_aio_comp;
672 if (journaling) {
673 // in-flight ops are flushed prior to closing the journal
674 uint64_t journal_tid = image_ctx.journal->append_io_event(
675 journal::EventEntry(journal::AioFlushEvent()),
b32b8144 676 ObjectRequests(), 0, 0, false, 0);
7c673cae
FG
677
678 aio_comp->set_request_count(1);
679 aio_comp->associate_journal_event(journal_tid);
680
681 FunctionContext *flush_ctx = new FunctionContext(
682 [aio_comp, &image_ctx, journal_tid] (int r) {
683 auto ctx = new C_FlushJournalCommit<I>(image_ctx, aio_comp,
684 journal_tid);
685 image_ctx.journal->flush_event(journal_tid, ctx);
686
687 // track flush op for block writes
688 aio_comp->start_op(true);
689 aio_comp->put();
690 });
691
692 image_ctx.flush_async_operations(flush_ctx);
693 } else {
694 // flush rbd cache only when journaling is not enabled
695 aio_comp->set_request_count(1);
696 C_AioRequest *req_comp = new C_AioRequest(aio_comp);
697 image_ctx.flush(req_comp);
698
699 aio_comp->start_op(true);
700 aio_comp->put();
701 }
702
703 image_ctx.perfcounter->inc(l_librbd_aio_flush);
704}
705
706template <typename I>
707void ImageFlushRequest<I>::send_image_cache_request() {
708 I &image_ctx = this->m_image_ctx;
709 assert(image_ctx.image_cache != nullptr);
710
711 AioCompletion *aio_comp = this->m_aio_comp;
712 aio_comp->set_request_count(1);
713 C_AioRequest *req_comp = new C_AioRequest(aio_comp);
714 image_ctx.image_cache->aio_flush(req_comp);
715}
716
717template <typename I>
718bool ImageWriteSameRequest<I>::assemble_writesame_extent(const ObjectExtent &object_extent,
719 bufferlist *bl, bool force_write) {
720 size_t m_data_len = m_data_bl.length();
721
722 if (!force_write) {
723 bool may_writesame = true;
724
725 for (auto q = object_extent.buffer_extents.begin();
726 q != object_extent.buffer_extents.end(); ++q) {
727 if (!(q->first % m_data_len == 0 && q->second % m_data_len == 0)) {
728 may_writesame = false;
729 break;
730 }
731 }
732
733 if (may_writesame) {
734 bl->append(m_data_bl);
735 return true;
736 }
737 }
738
739 for (auto q = object_extent.buffer_extents.begin();
740 q != object_extent.buffer_extents.end(); ++q) {
741 bufferlist sub_bl;
742 uint64_t sub_off = q->first % m_data_len;
743 uint64_t sub_len = m_data_len - sub_off;
744 uint64_t extent_left = q->second;
745 while (extent_left >= sub_len) {
746 sub_bl.substr_of(m_data_bl, sub_off, sub_len);
747 bl->claim_append(sub_bl);
748 extent_left -= sub_len;
749 if (sub_off) {
750 sub_off = 0;
751 sub_len = m_data_len;
752 }
753 }
754 if (extent_left) {
755 sub_bl.substr_of(m_data_bl, sub_off, extent_left);
756 bl->claim_append(sub_bl);
757 }
758 }
759 return false;
760}
761
762template <typename I>
763uint64_t ImageWriteSameRequest<I>::append_journal_event(
764 const ObjectRequests &requests, bool synchronous) {
765 I &image_ctx = this->m_image_ctx;
766
767 uint64_t tid = 0;
768 assert(!this->m_image_extents.empty());
769 for (auto &extent : this->m_image_extents) {
770 journal::EventEntry event_entry(journal::AioWriteSameEvent(extent.first,
771 extent.second,
772 m_data_bl));
773 tid = image_ctx.journal->append_io_event(std::move(event_entry),
774 requests, extent.first,
b32b8144 775 extent.second, synchronous, 0);
7c673cae
FG
776 }
777
778 if (image_ctx.object_cacher == NULL) {
779 AioCompletion *aio_comp = this->m_aio_comp;
780 aio_comp->associate_journal_event(tid);
781 }
782 return tid;
783}
784
785template <typename I>
786void ImageWriteSameRequest<I>::send_image_cache_request() {
787 I &image_ctx = this->m_image_ctx;
788 assert(image_ctx.image_cache != nullptr);
789
790 AioCompletion *aio_comp = this->m_aio_comp;
791 aio_comp->set_request_count(this->m_image_extents.size());
792 for (auto &extent : this->m_image_extents) {
793 C_AioRequest *req_comp = new C_AioRequest(aio_comp);
794 image_ctx.image_cache->aio_writesame(extent.first, extent.second,
795 std::move(m_data_bl), m_op_flags,
796 req_comp);
797 }
798}
799
800template <typename I>
801void ImageWriteSameRequest<I>::send_object_cache_requests(
802 const ObjectExtents &object_extents, uint64_t journal_tid) {
803 I &image_ctx = this->m_image_ctx;
804 for (auto p = object_extents.begin(); p != object_extents.end(); ++p) {
805 const ObjectExtent &object_extent = *p;
806
807 bufferlist bl;
808 assemble_writesame_extent(object_extent, &bl, true);
809
810 AioCompletion *aio_comp = this->m_aio_comp;
811 C_AioRequest *req_comp = new C_AioRequest(aio_comp);
31f18b77
FG
812 image_ctx.write_to_cache(
813 object_extent.oid, bl, object_extent.length, object_extent.offset,
814 req_comp, m_op_flags, journal_tid,
815 (this->m_trace.valid() ? &this->m_trace : nullptr));
7c673cae
FG
816 }
817}
818
819template <typename I>
820void ImageWriteSameRequest<I>::send_object_requests(
821 const ObjectExtents &object_extents, const ::SnapContext &snapc,
822 ObjectRequests *object_requests) {
823 I &image_ctx = this->m_image_ctx;
824
825 // cache handles creating object requests during writeback
826 if (image_ctx.object_cacher == NULL) {
827 AbstractImageWriteRequest<I>::send_object_requests(object_extents, snapc,
828 object_requests);
829 }
830}
831
832template <typename I>
833ObjectRequestHandle *ImageWriteSameRequest<I>::create_object_request(
834 const ObjectExtent &object_extent, const ::SnapContext &snapc,
835 Context *on_finish) {
836 I &image_ctx = this->m_image_ctx;
837 assert(image_ctx.object_cacher == NULL);
838
839 bufferlist bl;
840 ObjectRequest<I> *req;
841
842 if (assemble_writesame_extent(object_extent, &bl, false)) {
843 req = ObjectRequest<I>::create_writesame(
844 &image_ctx, object_extent.oid.name, object_extent.objectno,
845 object_extent.offset, object_extent.length,
31f18b77 846 bl, snapc, m_op_flags, this->m_trace, on_finish);
7c673cae
FG
847 return req;
848 }
849 req = ObjectRequest<I>::create_write(
850 &image_ctx, object_extent.oid.name, object_extent.objectno,
31f18b77 851 object_extent.offset, bl, snapc, m_op_flags, this->m_trace, on_finish);
7c673cae
FG
852 return req;
853}
854
855template <typename I>
856void ImageWriteSameRequest<I>::update_stats(size_t length) {
857 I &image_ctx = this->m_image_ctx;
858 image_ctx.perfcounter->inc(l_librbd_ws);
859 image_ctx.perfcounter->inc(l_librbd_ws_bytes, length);
860}
861
c07f9fc5
FG
862template <typename I>
863uint64_t ImageCompareAndWriteRequest<I>::append_journal_event(
864 const ObjectRequests &requests, bool synchronous) {
865
866 I &image_ctx = this->m_image_ctx;
867
868 uint64_t tid = 0;
869 assert(this->m_image_extents.size() == 1);
870 auto &extent = this->m_image_extents.front();
871 journal::EventEntry event_entry(journal::AioCompareAndWriteEvent(extent.first,
872 extent.second,
873 m_cmp_bl, m_bl));
874 tid = image_ctx.journal->append_io_event(std::move(event_entry),
875 requests, extent.first,
b32b8144 876 extent.second, synchronous, -EILSEQ);
c07f9fc5
FG
877
878 AioCompletion *aio_comp = this->m_aio_comp;
879 aio_comp->associate_journal_event(tid);
880
881 return tid;
882}
883
884template <typename I>
885void ImageCompareAndWriteRequest<I>::send_object_cache_requests(
886 const ObjectExtents &object_extents, uint64_t journal_tid) {
887 I &image_ctx = this->m_image_ctx;
888
889 if (image_ctx.object_cacher != NULL) {
890 Mutex::Locker cache_locker(image_ctx.cache_lock);
891 image_ctx.object_cacher->discard_set(image_ctx.object_set,
892 object_extents);
893 }
894}
895
896template <typename I>
897void ImageCompareAndWriteRequest<I>::assemble_extent(
898 const ObjectExtent &object_extent, bufferlist *bl) {
899 for (auto q = object_extent.buffer_extents.begin();
900 q != object_extent.buffer_extents.end(); ++q) {
901 bufferlist sub_bl;
902 sub_bl.substr_of(m_bl, q->first, q->second);
903 bl->claim_append(sub_bl);
904 }
905}
906
907template <typename I>
908void ImageCompareAndWriteRequest<I>::send_image_cache_request() {
909 I &image_ctx = this->m_image_ctx;
910 assert(image_ctx.image_cache != nullptr);
911
912 AioCompletion *aio_comp = this->m_aio_comp;
913 aio_comp->set_request_count(1);
914 C_AioRequest *req_comp = new C_AioRequest(aio_comp);
915 image_ctx.image_cache->aio_compare_and_write(
916 std::move(this->m_image_extents), std::move(m_cmp_bl), std::move(m_bl),
917 m_mismatch_offset, m_op_flags, req_comp);
918}
919
920template <typename I>
921ObjectRequestHandle *ImageCompareAndWriteRequest<I>::create_object_request(
922 const ObjectExtent &object_extent,
923 const ::SnapContext &snapc,
924 Context *on_finish) {
925 I &image_ctx = this->m_image_ctx;
926
927 bufferlist bl;
928 assemble_extent(object_extent, &bl);
929 ObjectRequest<I> *req = ObjectRequest<I>::create_compare_and_write(
930 &image_ctx, object_extent.oid.name,
931 object_extent.objectno, object_extent.offset,
932 m_cmp_bl, bl, snapc, m_mismatch_offset,
933 m_op_flags, this->m_trace, on_finish);
934 return req;
935}
936
937template <typename I>
938void ImageCompareAndWriteRequest<I>::update_stats(size_t length) {
939 I &image_ctx = this->m_image_ctx;
940 image_ctx.perfcounter->inc(l_librbd_cmp);
941 image_ctx.perfcounter->inc(l_librbd_cmp_bytes, length);
942}
943
944template <typename I>
945int ImageCompareAndWriteRequest<I>::prune_object_extents(ObjectExtents &object_extents) {
946 if (object_extents.size() > 1)
947 return -EINVAL;
948
949 I &image_ctx = this->m_image_ctx;
950 uint64_t sector_size = 512ULL;
951 uint64_t su = image_ctx.layout.stripe_unit;
952 ObjectExtent object_extent = object_extents.front();
953 if (object_extent.offset % sector_size + object_extent.length > sector_size ||
954 (su != 0 && (object_extent.offset % su + object_extent.length > su)))
955 return -EINVAL;
956
957 return 0;
958}
959
7c673cae
FG
960} // namespace io
961} // namespace librbd
962
963template class librbd::io::ImageRequest<librbd::ImageCtx>;
964template class librbd::io::ImageReadRequest<librbd::ImageCtx>;
965template class librbd::io::AbstractImageWriteRequest<librbd::ImageCtx>;
966template class librbd::io::ImageWriteRequest<librbd::ImageCtx>;
967template class librbd::io::ImageDiscardRequest<librbd::ImageCtx>;
968template class librbd::io::ImageFlushRequest<librbd::ImageCtx>;
969template class librbd::io::ImageWriteSameRequest<librbd::ImageCtx>;
c07f9fc5 970template class librbd::io::ImageCompareAndWriteRequest<librbd::ImageCtx>;