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/ImageRequest.h"
5 #include "librbd/ImageCtx.h"
6 #include "librbd/internal.h"
7 #include "librbd/Journal.h"
8 #include "librbd/Utils.h"
9 #include "librbd/cache/ImageCache.h"
10 #include "librbd/io/AioCompletion.h"
11 #include "librbd/io/ObjectRequest.h"
12 #include "librbd/journal/Types.h"
13 #include "include/rados/librados.hpp"
14 #include "common/WorkQueue.h"
15 #include "osdc/Striper.h"
17 #define dout_subsys ceph_subsys_rbd
19 #define dout_prefix *_dout << "librbd::io::ImageRequest: " << this \
20 << " " << __func__ << ": "
25 using util::get_image_ctx
;
29 template <typename ImageCtxT
= ImageCtx
>
30 struct C_DiscardJournalCommit
: public Context
{
31 typedef std::vector
<ObjectExtent
> ObjectExtents
;
34 AioCompletion
*aio_comp
;
35 ObjectExtents object_extents
;
37 C_DiscardJournalCommit(ImageCtxT
&_image_ctx
, AioCompletion
*_aio_comp
,
38 const ObjectExtents
&_object_extents
, uint64_t tid
)
39 : image_ctx(_image_ctx
), aio_comp(_aio_comp
),
40 object_extents(_object_extents
) {
41 CephContext
*cct
= image_ctx
.cct
;
42 ldout(cct
, 20) << "delaying cache discard until journal tid " << tid
<< " "
45 aio_comp
->add_request();
48 void finish(int r
) override
{
49 CephContext
*cct
= image_ctx
.cct
;
50 ldout(cct
, 20) << "C_DiscardJournalCommit: "
51 << "journal committed: discarding from cache" << dendl
;
53 Mutex::Locker
cache_locker(image_ctx
.cache_lock
);
54 image_ctx
.object_cacher
->discard_set(image_ctx
.object_set
, object_extents
);
55 aio_comp
->complete_request(r
);
59 template <typename ImageCtxT
= ImageCtx
>
60 struct C_FlushJournalCommit
: public Context
{
62 AioCompletion
*aio_comp
;
64 C_FlushJournalCommit(ImageCtxT
&_image_ctx
, AioCompletion
*_aio_comp
,
66 : image_ctx(_image_ctx
), aio_comp(_aio_comp
) {
67 CephContext
*cct
= image_ctx
.cct
;
68 ldout(cct
, 20) << "delaying flush until journal tid " << tid
<< " "
71 aio_comp
->add_request();
74 void finish(int r
) override
{
75 CephContext
*cct
= image_ctx
.cct
;
76 ldout(cct
, 20) << "C_FlushJournalCommit: journal committed" << dendl
;
77 aio_comp
->complete_request(r
);
81 template <typename ImageCtxT
>
82 class C_ObjectCacheRead
: public Context
{
84 explicit C_ObjectCacheRead(ImageCtxT
&ictx
, ObjectReadRequest
<ImageCtxT
> *req
)
85 : m_image_ctx(ictx
), m_req(req
), m_enqueued(false) {}
87 void complete(int r
) override
{
89 // cache_lock creates a lock ordering issue -- so re-execute this context
90 // outside the cache_lock
92 m_image_ctx
.op_work_queue
->queue(this, r
);
99 void finish(int r
) override
{
104 ImageCtxT
&m_image_ctx
;
105 ObjectReadRequest
<ImageCtxT
> *m_req
;
109 } // anonymous namespace
111 template <typename I
>
112 ImageRequest
<I
>* ImageRequest
<I
>::create_read_request(
113 I
&image_ctx
, AioCompletion
*aio_comp
, Extents
&&image_extents
,
114 ReadResult
&&read_result
, int op_flags
,
115 const ZTracer::Trace
&parent_trace
) {
116 return new ImageReadRequest
<I
>(image_ctx
, aio_comp
,
117 std::move(image_extents
),
118 std::move(read_result
), op_flags
,
122 template <typename I
>
123 ImageRequest
<I
>* ImageRequest
<I
>::create_write_request(
124 I
&image_ctx
, AioCompletion
*aio_comp
, Extents
&&image_extents
,
125 bufferlist
&&bl
, int op_flags
, const ZTracer::Trace
&parent_trace
) {
126 return new ImageWriteRequest
<I
>(image_ctx
, aio_comp
, std::move(image_extents
),
127 std::move(bl
), op_flags
, parent_trace
);
130 template <typename I
>
131 ImageRequest
<I
>* ImageRequest
<I
>::create_discard_request(
132 I
&image_ctx
, AioCompletion
*aio_comp
, uint64_t off
, uint64_t len
,
133 bool skip_partial_discard
, const ZTracer::Trace
&parent_trace
) {
134 return new ImageDiscardRequest
<I
>(image_ctx
, aio_comp
, off
, len
,
135 skip_partial_discard
, parent_trace
);
138 template <typename I
>
139 ImageRequest
<I
>* ImageRequest
<I
>::create_flush_request(
140 I
&image_ctx
, AioCompletion
*aio_comp
,
141 const ZTracer::Trace
&parent_trace
) {
142 return new ImageFlushRequest
<I
>(image_ctx
, aio_comp
, parent_trace
);
145 template <typename I
>
146 ImageRequest
<I
>* ImageRequest
<I
>::create_writesame_request(
147 I
&image_ctx
, AioCompletion
*aio_comp
, uint64_t off
, uint64_t len
,
148 bufferlist
&&bl
, int op_flags
, const ZTracer::Trace
&parent_trace
) {
149 return new ImageWriteSameRequest
<I
>(image_ctx
, aio_comp
, off
, len
,
150 std::move(bl
), op_flags
, parent_trace
);
153 template <typename I
>
154 ImageRequest
<I
>* ImageRequest
<I
>::create_compare_and_write_request(
155 I
&image_ctx
, AioCompletion
*c
, Extents
&&image_extents
,
156 bufferlist
&&cmp_bl
, bufferlist
&&bl
, uint64_t *mismatch_offset
,
157 int op_flags
, const ZTracer::Trace
&parent_trace
) {
158 return new ImageCompareAndWriteRequest
<I
>(image_ctx
, c
,
159 std::move(image_extents
),
161 std::move(bl
), mismatch_offset
,
162 op_flags
, parent_trace
);
165 template <typename I
>
166 void ImageRequest
<I
>::aio_read(I
*ictx
, AioCompletion
*c
,
167 Extents
&&image_extents
,
168 ReadResult
&&read_result
, int op_flags
,
169 const ZTracer::Trace
&parent_trace
) {
170 ImageReadRequest
<I
> req(*ictx
, c
, std::move(image_extents
),
171 std::move(read_result
), op_flags
, parent_trace
);
175 template <typename I
>
176 void ImageRequest
<I
>::aio_write(I
*ictx
, AioCompletion
*c
,
177 Extents
&&image_extents
, bufferlist
&&bl
,
179 const ZTracer::Trace
&parent_trace
) {
180 ImageWriteRequest
<I
> req(*ictx
, c
, std::move(image_extents
), std::move(bl
),
181 op_flags
, parent_trace
);
185 template <typename I
>
186 void ImageRequest
<I
>::aio_discard(I
*ictx
, AioCompletion
*c
,
187 uint64_t off
, uint64_t len
,
188 bool skip_partial_discard
,
189 const ZTracer::Trace
&parent_trace
) {
190 ImageDiscardRequest
<I
> req(*ictx
, c
, off
, len
, skip_partial_discard
,
195 template <typename I
>
196 void ImageRequest
<I
>::aio_flush(I
*ictx
, AioCompletion
*c
,
197 const ZTracer::Trace
&parent_trace
) {
198 ImageFlushRequest
<I
> req(*ictx
, c
, parent_trace
);
202 template <typename I
>
203 void ImageRequest
<I
>::aio_writesame(I
*ictx
, AioCompletion
*c
,
204 uint64_t off
, uint64_t len
,
205 bufferlist
&&bl
, int op_flags
,
206 const ZTracer::Trace
&parent_trace
) {
207 ImageWriteSameRequest
<I
> req(*ictx
, c
, off
, len
, std::move(bl
), op_flags
,
212 template <typename I
>
213 void ImageRequest
<I
>::aio_compare_and_write(I
*ictx
, AioCompletion
*c
,
214 Extents
&&image_extents
,
217 uint64_t *mismatch_offset
,
219 const ZTracer::Trace
&parent_trace
) {
220 ImageCompareAndWriteRequest
<I
> req(*ictx
, c
, std::move(image_extents
),
221 std::move(cmp_bl
), std::move(bl
),
222 mismatch_offset
, op_flags
, parent_trace
);
227 template <typename I
>
228 void ImageRequest
<I
>::send() {
229 I
&image_ctx
= this->m_image_ctx
;
230 assert(m_aio_comp
->is_initialized(get_aio_type()));
231 assert(m_aio_comp
->is_started() ^ (get_aio_type() == AIO_TYPE_FLUSH
));
233 CephContext
*cct
= image_ctx
.cct
;
234 AioCompletion
*aio_comp
= this->m_aio_comp
;
235 ldout(cct
, 20) << get_request_type() << ": ictx=" << &image_ctx
<< ", "
236 << "completion=" << aio_comp
<< dendl
;
239 int r
= clip_request();
245 if (m_bypass_image_cache
|| m_image_ctx
.image_cache
== nullptr) {
248 send_image_cache_request();
252 template <typename I
>
253 int ImageRequest
<I
>::clip_request() {
254 RWLock::RLocker
snap_locker(m_image_ctx
.snap_lock
);
255 for (auto &image_extent
: m_image_extents
) {
256 auto clip_len
= image_extent
.second
;
257 int r
= clip_io(get_image_ctx(&m_image_ctx
), image_extent
.first
, &clip_len
);
262 image_extent
.second
= clip_len
;
267 template <typename I
>
268 void ImageRequest
<I
>::start_op() {
269 m_aio_comp
->start_op();
272 template <typename I
>
273 void ImageRequest
<I
>::fail(int r
) {
274 AioCompletion
*aio_comp
= this->m_aio_comp
;
279 template <typename I
>
280 ImageReadRequest
<I
>::ImageReadRequest(I
&image_ctx
, AioCompletion
*aio_comp
,
281 Extents
&&image_extents
,
282 ReadResult
&&read_result
, int op_flags
,
283 const ZTracer::Trace
&parent_trace
)
284 : ImageRequest
<I
>(image_ctx
, aio_comp
, std::move(image_extents
), "read",
286 m_op_flags(op_flags
) {
287 aio_comp
->read_result
= std::move(read_result
);
290 template <typename I
>
291 int ImageReadRequest
<I
>::clip_request() {
292 int r
= ImageRequest
<I
>::clip_request();
297 uint64_t buffer_length
= 0;
298 auto &image_extents
= this->m_image_extents
;
299 for (auto &image_extent
: image_extents
) {
300 buffer_length
+= image_extent
.second
;
302 this->m_aio_comp
->read_result
.set_clip_length(buffer_length
);
306 template <typename I
>
307 void ImageReadRequest
<I
>::send_request() {
308 I
&image_ctx
= this->m_image_ctx
;
309 CephContext
*cct
= image_ctx
.cct
;
311 auto &image_extents
= this->m_image_extents
;
312 if (image_ctx
.object_cacher
&& image_ctx
.readahead_max_bytes
> 0 &&
313 !(m_op_flags
& LIBRADOS_OP_FLAG_FADVISE_RANDOM
)) {
314 readahead(get_image_ctx(&image_ctx
), image_extents
);
317 AioCompletion
*aio_comp
= this->m_aio_comp
;
318 librados::snap_t snap_id
;
319 map
<object_t
,vector
<ObjectExtent
> > object_extents
;
320 uint64_t buffer_ofs
= 0;
322 // prevent image size from changing between computing clip and recording
323 // pending async operation
324 RWLock::RLocker
snap_locker(image_ctx
.snap_lock
);
325 snap_id
= image_ctx
.snap_id
;
327 // map image extents to object extents
328 for (auto &extent
: image_extents
) {
329 if (extent
.second
== 0) {
333 Striper::file_to_extents(cct
, image_ctx
.format_string
, &image_ctx
.layout
,
334 extent
.first
, extent
.second
, 0, object_extents
,
336 buffer_ofs
+= extent
.second
;
340 // pre-calculate the expected number of read requests
341 uint32_t request_count
= 0;
342 for (auto &object_extent
: object_extents
) {
343 request_count
+= object_extent
.second
.size();
345 aio_comp
->set_request_count(request_count
);
347 // issue the requests
348 for (auto &object_extent
: object_extents
) {
349 for (auto &extent
: object_extent
.second
) {
350 ldout(cct
, 20) << "oid " << extent
.oid
<< " " << extent
.offset
<< "~"
351 << extent
.length
<< " from " << extent
.buffer_extents
354 auto req_comp
= new io::ReadResult::C_SparseReadRequest
<I
>(
356 ObjectReadRequest
<I
> *req
= ObjectReadRequest
<I
>::create(
357 &image_ctx
, extent
.oid
.name
, extent
.objectno
, extent
.offset
,
358 extent
.length
, extent
.buffer_extents
, snap_id
, true, m_op_flags
,
359 this->m_trace
, req_comp
);
360 req_comp
->request
= req
;
362 if (image_ctx
.object_cacher
) {
363 C_ObjectCacheRead
<I
> *cache_comp
= new C_ObjectCacheRead
<I
>(image_ctx
,
365 image_ctx
.aio_read_from_cache(
366 extent
.oid
, extent
.objectno
, &req
->data(), extent
.length
,
367 extent
.offset
, cache_comp
, m_op_flags
,
368 (this->m_trace
.valid() ? &this->m_trace
: nullptr));
377 image_ctx
.perfcounter
->inc(l_librbd_rd
);
378 image_ctx
.perfcounter
->inc(l_librbd_rd_bytes
, buffer_ofs
);
381 template <typename I
>
382 void ImageReadRequest
<I
>::send_image_cache_request() {
383 I
&image_ctx
= this->m_image_ctx
;
384 assert(image_ctx
.image_cache
!= nullptr);
386 AioCompletion
*aio_comp
= this->m_aio_comp
;
387 aio_comp
->set_request_count(1);
389 auto *req_comp
= new io::ReadResult::C_ImageReadRequest(
390 aio_comp
, this->m_image_extents
);
391 image_ctx
.image_cache
->aio_read(std::move(this->m_image_extents
),
392 &req_comp
->bl
, m_op_flags
,
396 template <typename I
>
397 void AbstractImageWriteRequest
<I
>::send_request() {
398 I
&image_ctx
= this->m_image_ctx
;
399 CephContext
*cct
= image_ctx
.cct
;
401 RWLock::RLocker
md_locker(image_ctx
.md_lock
);
403 bool journaling
= false;
405 AioCompletion
*aio_comp
= this->m_aio_comp
;
406 uint64_t clip_len
= 0;
407 ObjectExtents object_extents
;
410 // prevent image size from changing between computing clip and recording
411 // pending async operation
412 RWLock::RLocker
snap_locker(image_ctx
.snap_lock
);
413 if (image_ctx
.snap_id
!= CEPH_NOSNAP
|| image_ctx
.read_only
) {
414 aio_comp
->fail(-EROFS
);
418 for (auto &extent
: this->m_image_extents
) {
419 if (extent
.second
== 0) {
423 // map to object extents
424 Striper::file_to_extents(cct
, image_ctx
.format_string
, &image_ctx
.layout
,
425 extent
.first
, extent
.second
, 0, object_extents
);
426 clip_len
+= extent
.second
;
429 snapc
= image_ctx
.snapc
;
430 journaling
= (image_ctx
.journal
!= nullptr &&
431 image_ctx
.journal
->is_journal_appending());
434 int ret
= prune_object_extents(object_extents
);
440 if (!object_extents
.empty()) {
441 uint64_t journal_tid
= 0;
442 aio_comp
->set_request_count(
443 object_extents
.size() + get_object_cache_request_count(journaling
));
445 ObjectRequests requests
;
446 send_object_requests(object_extents
, snapc
,
447 (journaling
? &requests
: nullptr));
450 // in-flight ops are flushed prior to closing the journal
451 assert(image_ctx
.journal
!= NULL
);
452 journal_tid
= append_journal_event(requests
, m_synchronous
);
455 if (image_ctx
.object_cacher
!= NULL
) {
456 send_object_cache_requests(object_extents
, journal_tid
);
459 // no IO to perform -- fire completion
463 update_stats(clip_len
);
467 template <typename I
>
468 void AbstractImageWriteRequest
<I
>::send_object_requests(
469 const ObjectExtents
&object_extents
, const ::SnapContext
&snapc
,
470 ObjectRequests
*object_requests
) {
471 I
&image_ctx
= this->m_image_ctx
;
472 CephContext
*cct
= image_ctx
.cct
;
474 AioCompletion
*aio_comp
= this->m_aio_comp
;
475 for (ObjectExtents::const_iterator p
= object_extents
.begin();
476 p
!= object_extents
.end(); ++p
) {
477 ldout(cct
, 20) << "oid " << p
->oid
<< " " << p
->offset
<< "~" << p
->length
478 << " from " << p
->buffer_extents
<< dendl
;
479 C_AioRequest
*req_comp
= new C_AioRequest(aio_comp
);
480 ObjectRequestHandle
*request
= create_object_request(*p
, snapc
,
483 // if journaling, stash the request for later; otherwise send
484 if (request
!= NULL
) {
485 if (object_requests
!= NULL
) {
486 object_requests
->push_back(request
);
494 template <typename I
>
495 void ImageWriteRequest
<I
>::assemble_extent(const ObjectExtent
&object_extent
,
497 for (auto q
= object_extent
.buffer_extents
.begin();
498 q
!= object_extent
.buffer_extents
.end(); ++q
) {
500 sub_bl
.substr_of(m_bl
, q
->first
, q
->second
);
501 bl
->claim_append(sub_bl
);
505 template <typename I
>
506 uint64_t ImageWriteRequest
<I
>::append_journal_event(
507 const ObjectRequests
&requests
, bool synchronous
) {
508 I
&image_ctx
= this->m_image_ctx
;
511 uint64_t buffer_offset
= 0;
512 assert(!this->m_image_extents
.empty());
513 for (auto &extent
: this->m_image_extents
) {
515 sub_bl
.substr_of(m_bl
, buffer_offset
, extent
.second
);
516 buffer_offset
+= extent
.second
;
518 tid
= image_ctx
.journal
->append_write_event(extent
.first
, extent
.second
,
519 sub_bl
, requests
, synchronous
);
522 if (image_ctx
.object_cacher
== NULL
) {
523 AioCompletion
*aio_comp
= this->m_aio_comp
;
524 aio_comp
->associate_journal_event(tid
);
529 template <typename I
>
530 void ImageWriteRequest
<I
>::send_image_cache_request() {
531 I
&image_ctx
= this->m_image_ctx
;
532 assert(image_ctx
.image_cache
!= nullptr);
534 AioCompletion
*aio_comp
= this->m_aio_comp
;
535 aio_comp
->set_request_count(1);
536 C_AioRequest
*req_comp
= new C_AioRequest(aio_comp
);
537 image_ctx
.image_cache
->aio_write(std::move(this->m_image_extents
),
538 std::move(m_bl
), m_op_flags
, req_comp
);
541 template <typename I
>
542 void ImageWriteRequest
<I
>::send_object_cache_requests(
543 const ObjectExtents
&object_extents
, uint64_t journal_tid
) {
544 I
&image_ctx
= this->m_image_ctx
;
545 for (auto p
= object_extents
.begin(); p
!= object_extents
.end(); ++p
) {
546 const ObjectExtent
&object_extent
= *p
;
549 assemble_extent(object_extent
, &bl
);
551 AioCompletion
*aio_comp
= this->m_aio_comp
;
552 C_AioRequest
*req_comp
= new C_AioRequest(aio_comp
);
553 image_ctx
.write_to_cache(
554 object_extent
.oid
, bl
, object_extent
.length
, object_extent
.offset
,
555 req_comp
, m_op_flags
, journal_tid
,
556 (this->m_trace
.valid() ? &this->m_trace
: nullptr));
560 template <typename I
>
561 void ImageWriteRequest
<I
>::send_object_requests(
562 const ObjectExtents
&object_extents
, const ::SnapContext
&snapc
,
563 ObjectRequests
*object_requests
) {
564 I
&image_ctx
= this->m_image_ctx
;
566 // cache handles creating object requests during writeback
567 if (image_ctx
.object_cacher
== NULL
) {
568 AbstractImageWriteRequest
<I
>::send_object_requests(object_extents
, snapc
,
573 template <typename I
>
574 ObjectRequestHandle
*ImageWriteRequest
<I
>::create_object_request(
575 const ObjectExtent
&object_extent
, const ::SnapContext
&snapc
,
576 Context
*on_finish
) {
577 I
&image_ctx
= this->m_image_ctx
;
578 assert(image_ctx
.object_cacher
== NULL
);
581 assemble_extent(object_extent
, &bl
);
582 ObjectRequest
<I
> *req
= ObjectRequest
<I
>::create_write(
583 &image_ctx
, object_extent
.oid
.name
, object_extent
.objectno
,
584 object_extent
.offset
, bl
, snapc
, m_op_flags
, this->m_trace
, on_finish
);
588 template <typename I
>
589 void ImageWriteRequest
<I
>::update_stats(size_t length
) {
590 I
&image_ctx
= this->m_image_ctx
;
591 image_ctx
.perfcounter
->inc(l_librbd_wr
);
592 image_ctx
.perfcounter
->inc(l_librbd_wr_bytes
, length
);
595 template <typename I
>
596 uint64_t ImageDiscardRequest
<I
>::append_journal_event(
597 const ObjectRequests
&requests
, bool synchronous
) {
598 I
&image_ctx
= this->m_image_ctx
;
601 assert(!this->m_image_extents
.empty());
602 for (auto &extent
: this->m_image_extents
) {
603 journal::EventEntry
event_entry(journal::AioDiscardEvent(extent
.first
,
605 this->m_skip_partial_discard
));
606 tid
= image_ctx
.journal
->append_io_event(std::move(event_entry
),
607 requests
, extent
.first
,
608 extent
.second
, synchronous
);
611 AioCompletion
*aio_comp
= this->m_aio_comp
;
612 aio_comp
->associate_journal_event(tid
);
616 template <typename I
>
617 int ImageDiscardRequest
<I
>::prune_object_extents(ObjectExtents
&object_extents
) {
618 I
&image_ctx
= this->m_image_ctx
;
619 CephContext
*cct
= image_ctx
.cct
;
620 if (!this->m_skip_partial_discard
) {
624 for (auto p
= object_extents
.begin(); p
!= object_extents
.end(); ) {
625 if (p
->offset
+ p
->length
< image_ctx
.layout
.object_size
) {
626 ldout(cct
, 20) << "oid " << p
->oid
<< " " << p
->offset
<< "~"
627 << p
->length
<< " from " << p
->buffer_extents
628 << ": skip partial discard" << dendl
;
629 p
= object_extents
.erase(p
);
638 template <typename I
>
639 uint32_t ImageDiscardRequest
<I
>::get_object_cache_request_count(bool journaling
) const {
640 // extra completion request is required for tracking journal commit
641 I
&image_ctx
= this->m_image_ctx
;
642 return (image_ctx
.object_cacher
!= nullptr && journaling
? 1 : 0);
645 template <typename I
>
646 void ImageDiscardRequest
<I
>::send_image_cache_request() {
647 I
&image_ctx
= this->m_image_ctx
;
648 assert(image_ctx
.image_cache
!= nullptr);
650 AioCompletion
*aio_comp
= this->m_aio_comp
;
651 aio_comp
->set_request_count(this->m_image_extents
.size());
652 for (auto &extent
: this->m_image_extents
) {
653 C_AioRequest
*req_comp
= new C_AioRequest(aio_comp
);
654 image_ctx
.image_cache
->aio_discard(extent
.first
, extent
.second
,
655 this->m_skip_partial_discard
, req_comp
);
659 template <typename I
>
660 void ImageDiscardRequest
<I
>::send_object_cache_requests(
661 const ObjectExtents
&object_extents
, uint64_t journal_tid
) {
662 I
&image_ctx
= this->m_image_ctx
;
663 if (journal_tid
== 0) {
664 Mutex::Locker
cache_locker(image_ctx
.cache_lock
);
665 image_ctx
.object_cacher
->discard_set(image_ctx
.object_set
,
668 // cannot discard from cache until journal has committed
669 assert(image_ctx
.journal
!= NULL
);
670 AioCompletion
*aio_comp
= this->m_aio_comp
;
671 image_ctx
.journal
->wait_event(
672 journal_tid
, new C_DiscardJournalCommit
<I
>(image_ctx
, aio_comp
,
673 object_extents
, journal_tid
));
677 template <typename I
>
678 ObjectRequestHandle
*ImageDiscardRequest
<I
>::create_object_request(
679 const ObjectExtent
&object_extent
, const ::SnapContext
&snapc
,
680 Context
*on_finish
) {
681 I
&image_ctx
= this->m_image_ctx
;
683 ObjectRequest
<I
> *req
;
684 if (object_extent
.length
== image_ctx
.layout
.object_size
) {
685 req
= ObjectRequest
<I
>::create_remove(
686 &image_ctx
, object_extent
.oid
.name
, object_extent
.objectno
, snapc
,
687 this->m_trace
, on_finish
);
688 } else if (object_extent
.offset
+ object_extent
.length
==
689 image_ctx
.layout
.object_size
) {
690 req
= ObjectRequest
<I
>::create_truncate(
691 &image_ctx
, object_extent
.oid
.name
, object_extent
.objectno
,
692 object_extent
.offset
, snapc
, this->m_trace
, on_finish
);
694 req
= ObjectRequest
<I
>::create_zero(
695 &image_ctx
, object_extent
.oid
.name
, object_extent
.objectno
,
696 object_extent
.offset
, object_extent
.length
, snapc
,
697 this->m_trace
, on_finish
);
702 template <typename I
>
703 void ImageDiscardRequest
<I
>::update_stats(size_t length
) {
704 I
&image_ctx
= this->m_image_ctx
;
705 image_ctx
.perfcounter
->inc(l_librbd_discard
);
706 image_ctx
.perfcounter
->inc(l_librbd_discard_bytes
, length
);
709 template <typename I
>
710 void ImageFlushRequest
<I
>::send_request() {
711 I
&image_ctx
= this->m_image_ctx
;
712 image_ctx
.user_flushed();
714 bool journaling
= false;
716 RWLock::RLocker
snap_locker(image_ctx
.snap_lock
);
717 journaling
= (image_ctx
.journal
!= nullptr &&
718 image_ctx
.journal
->is_journal_appending());
721 AioCompletion
*aio_comp
= this->m_aio_comp
;
723 // in-flight ops are flushed prior to closing the journal
724 uint64_t journal_tid
= image_ctx
.journal
->append_io_event(
725 journal::EventEntry(journal::AioFlushEvent()),
726 ObjectRequests(), 0, 0, false);
728 aio_comp
->set_request_count(1);
729 aio_comp
->associate_journal_event(journal_tid
);
731 FunctionContext
*flush_ctx
= new FunctionContext(
732 [aio_comp
, &image_ctx
, journal_tid
] (int r
) {
733 auto ctx
= new C_FlushJournalCommit
<I
>(image_ctx
, aio_comp
,
735 image_ctx
.journal
->flush_event(journal_tid
, ctx
);
737 // track flush op for block writes
738 aio_comp
->start_op(true);
742 image_ctx
.flush_async_operations(flush_ctx
);
744 // flush rbd cache only when journaling is not enabled
745 aio_comp
->set_request_count(1);
746 C_AioRequest
*req_comp
= new C_AioRequest(aio_comp
);
747 image_ctx
.flush(req_comp
);
749 aio_comp
->start_op(true);
753 image_ctx
.perfcounter
->inc(l_librbd_aio_flush
);
756 template <typename I
>
757 void ImageFlushRequest
<I
>::send_image_cache_request() {
758 I
&image_ctx
= this->m_image_ctx
;
759 assert(image_ctx
.image_cache
!= nullptr);
761 AioCompletion
*aio_comp
= this->m_aio_comp
;
762 aio_comp
->set_request_count(1);
763 C_AioRequest
*req_comp
= new C_AioRequest(aio_comp
);
764 image_ctx
.image_cache
->aio_flush(req_comp
);
767 template <typename I
>
768 bool ImageWriteSameRequest
<I
>::assemble_writesame_extent(const ObjectExtent
&object_extent
,
769 bufferlist
*bl
, bool force_write
) {
770 size_t m_data_len
= m_data_bl
.length();
773 bool may_writesame
= true;
775 for (auto q
= object_extent
.buffer_extents
.begin();
776 q
!= object_extent
.buffer_extents
.end(); ++q
) {
777 if (!(q
->first
% m_data_len
== 0 && q
->second
% m_data_len
== 0)) {
778 may_writesame
= false;
784 bl
->append(m_data_bl
);
789 for (auto q
= object_extent
.buffer_extents
.begin();
790 q
!= object_extent
.buffer_extents
.end(); ++q
) {
792 uint64_t sub_off
= q
->first
% m_data_len
;
793 uint64_t sub_len
= m_data_len
- sub_off
;
794 uint64_t extent_left
= q
->second
;
795 while (extent_left
>= sub_len
) {
796 sub_bl
.substr_of(m_data_bl
, sub_off
, sub_len
);
797 bl
->claim_append(sub_bl
);
798 extent_left
-= sub_len
;
801 sub_len
= m_data_len
;
805 sub_bl
.substr_of(m_data_bl
, sub_off
, extent_left
);
806 bl
->claim_append(sub_bl
);
812 template <typename I
>
813 uint64_t ImageWriteSameRequest
<I
>::append_journal_event(
814 const ObjectRequests
&requests
, bool synchronous
) {
815 I
&image_ctx
= this->m_image_ctx
;
818 assert(!this->m_image_extents
.empty());
819 for (auto &extent
: this->m_image_extents
) {
820 journal::EventEntry
event_entry(journal::AioWriteSameEvent(extent
.first
,
823 tid
= image_ctx
.journal
->append_io_event(std::move(event_entry
),
824 requests
, extent
.first
,
825 extent
.second
, synchronous
);
828 if (image_ctx
.object_cacher
== NULL
) {
829 AioCompletion
*aio_comp
= this->m_aio_comp
;
830 aio_comp
->associate_journal_event(tid
);
835 template <typename I
>
836 void ImageWriteSameRequest
<I
>::send_image_cache_request() {
837 I
&image_ctx
= this->m_image_ctx
;
838 assert(image_ctx
.image_cache
!= nullptr);
840 AioCompletion
*aio_comp
= this->m_aio_comp
;
841 aio_comp
->set_request_count(this->m_image_extents
.size());
842 for (auto &extent
: this->m_image_extents
) {
843 C_AioRequest
*req_comp
= new C_AioRequest(aio_comp
);
844 image_ctx
.image_cache
->aio_writesame(extent
.first
, extent
.second
,
845 std::move(m_data_bl
), m_op_flags
,
850 template <typename I
>
851 void ImageWriteSameRequest
<I
>::send_object_cache_requests(
852 const ObjectExtents
&object_extents
, uint64_t journal_tid
) {
853 I
&image_ctx
= this->m_image_ctx
;
854 for (auto p
= object_extents
.begin(); p
!= object_extents
.end(); ++p
) {
855 const ObjectExtent
&object_extent
= *p
;
858 assemble_writesame_extent(object_extent
, &bl
, true);
860 AioCompletion
*aio_comp
= this->m_aio_comp
;
861 C_AioRequest
*req_comp
= new C_AioRequest(aio_comp
);
862 image_ctx
.write_to_cache(
863 object_extent
.oid
, bl
, object_extent
.length
, object_extent
.offset
,
864 req_comp
, m_op_flags
, journal_tid
,
865 (this->m_trace
.valid() ? &this->m_trace
: nullptr));
869 template <typename I
>
870 void ImageWriteSameRequest
<I
>::send_object_requests(
871 const ObjectExtents
&object_extents
, const ::SnapContext
&snapc
,
872 ObjectRequests
*object_requests
) {
873 I
&image_ctx
= this->m_image_ctx
;
875 // cache handles creating object requests during writeback
876 if (image_ctx
.object_cacher
== NULL
) {
877 AbstractImageWriteRequest
<I
>::send_object_requests(object_extents
, snapc
,
882 template <typename I
>
883 ObjectRequestHandle
*ImageWriteSameRequest
<I
>::create_object_request(
884 const ObjectExtent
&object_extent
, const ::SnapContext
&snapc
,
885 Context
*on_finish
) {
886 I
&image_ctx
= this->m_image_ctx
;
887 assert(image_ctx
.object_cacher
== NULL
);
890 ObjectRequest
<I
> *req
;
892 if (assemble_writesame_extent(object_extent
, &bl
, false)) {
893 req
= ObjectRequest
<I
>::create_writesame(
894 &image_ctx
, object_extent
.oid
.name
, object_extent
.objectno
,
895 object_extent
.offset
, object_extent
.length
,
896 bl
, snapc
, m_op_flags
, this->m_trace
, on_finish
);
899 req
= ObjectRequest
<I
>::create_write(
900 &image_ctx
, object_extent
.oid
.name
, object_extent
.objectno
,
901 object_extent
.offset
, bl
, snapc
, m_op_flags
, this->m_trace
, on_finish
);
905 template <typename I
>
906 void ImageWriteSameRequest
<I
>::update_stats(size_t length
) {
907 I
&image_ctx
= this->m_image_ctx
;
908 image_ctx
.perfcounter
->inc(l_librbd_ws
);
909 image_ctx
.perfcounter
->inc(l_librbd_ws_bytes
, length
);
912 template <typename I
>
913 uint64_t ImageCompareAndWriteRequest
<I
>::append_journal_event(
914 const ObjectRequests
&requests
, bool synchronous
) {
916 I
&image_ctx
= this->m_image_ctx
;
919 assert(this->m_image_extents
.size() == 1);
920 auto &extent
= this->m_image_extents
.front();
921 journal::EventEntry
event_entry(journal::AioCompareAndWriteEvent(extent
.first
,
924 tid
= image_ctx
.journal
->append_io_event(std::move(event_entry
),
925 requests
, extent
.first
,
926 extent
.second
, synchronous
);
928 AioCompletion
*aio_comp
= this->m_aio_comp
;
929 aio_comp
->associate_journal_event(tid
);
934 template <typename I
>
935 void ImageCompareAndWriteRequest
<I
>::send_object_cache_requests(
936 const ObjectExtents
&object_extents
, uint64_t journal_tid
) {
937 I
&image_ctx
= this->m_image_ctx
;
939 if (image_ctx
.object_cacher
!= NULL
) {
940 Mutex::Locker
cache_locker(image_ctx
.cache_lock
);
941 image_ctx
.object_cacher
->discard_set(image_ctx
.object_set
,
946 template <typename I
>
947 void ImageCompareAndWriteRequest
<I
>::assemble_extent(
948 const ObjectExtent
&object_extent
, bufferlist
*bl
) {
949 for (auto q
= object_extent
.buffer_extents
.begin();
950 q
!= object_extent
.buffer_extents
.end(); ++q
) {
952 sub_bl
.substr_of(m_bl
, q
->first
, q
->second
);
953 bl
->claim_append(sub_bl
);
957 template <typename I
>
958 void ImageCompareAndWriteRequest
<I
>::send_image_cache_request() {
959 I
&image_ctx
= this->m_image_ctx
;
960 assert(image_ctx
.image_cache
!= nullptr);
962 AioCompletion
*aio_comp
= this->m_aio_comp
;
963 aio_comp
->set_request_count(1);
964 C_AioRequest
*req_comp
= new C_AioRequest(aio_comp
);
965 image_ctx
.image_cache
->aio_compare_and_write(
966 std::move(this->m_image_extents
), std::move(m_cmp_bl
), std::move(m_bl
),
967 m_mismatch_offset
, m_op_flags
, req_comp
);
970 template <typename I
>
971 ObjectRequestHandle
*ImageCompareAndWriteRequest
<I
>::create_object_request(
972 const ObjectExtent
&object_extent
,
973 const ::SnapContext
&snapc
,
974 Context
*on_finish
) {
975 I
&image_ctx
= this->m_image_ctx
;
978 assemble_extent(object_extent
, &bl
);
979 ObjectRequest
<I
> *req
= ObjectRequest
<I
>::create_compare_and_write(
980 &image_ctx
, object_extent
.oid
.name
,
981 object_extent
.objectno
, object_extent
.offset
,
982 m_cmp_bl
, bl
, snapc
, m_mismatch_offset
,
983 m_op_flags
, this->m_trace
, on_finish
);
987 template <typename I
>
988 void ImageCompareAndWriteRequest
<I
>::update_stats(size_t length
) {
989 I
&image_ctx
= this->m_image_ctx
;
990 image_ctx
.perfcounter
->inc(l_librbd_cmp
);
991 image_ctx
.perfcounter
->inc(l_librbd_cmp_bytes
, length
);
994 template <typename I
>
995 int ImageCompareAndWriteRequest
<I
>::prune_object_extents(ObjectExtents
&object_extents
) {
996 if (object_extents
.size() > 1)
999 I
&image_ctx
= this->m_image_ctx
;
1000 uint64_t sector_size
= 512ULL;
1001 uint64_t su
= image_ctx
.layout
.stripe_unit
;
1002 ObjectExtent object_extent
= object_extents
.front();
1003 if (object_extent
.offset
% sector_size
+ object_extent
.length
> sector_size
||
1004 (su
!= 0 && (object_extent
.offset
% su
+ object_extent
.length
> su
)))
1011 } // namespace librbd
1013 template class librbd::io::ImageRequest
<librbd::ImageCtx
>;
1014 template class librbd::io::ImageReadRequest
<librbd::ImageCtx
>;
1015 template class librbd::io::AbstractImageWriteRequest
<librbd::ImageCtx
>;
1016 template class librbd::io::ImageWriteRequest
<librbd::ImageCtx
>;
1017 template class librbd::io::ImageDiscardRequest
<librbd::ImageCtx
>;
1018 template class librbd::io::ImageFlushRequest
<librbd::ImageCtx
>;
1019 template class librbd::io::ImageWriteSameRequest
<librbd::ImageCtx
>;
1020 template class librbd::io::ImageCompareAndWriteRequest
<librbd::ImageCtx
>;