]>
git.proxmox.com Git - ceph.git/blob - ceph/src/librbd/io/ObjectRequest.cc
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/ObjectRequest.h"
5 #include "common/ceph_context.h"
6 #include "common/dout.h"
7 #include "common/errno.h"
8 #include "common/Mutex.h"
9 #include "common/RWLock.h"
10 #include "common/WorkQueue.h"
11 #include "include/Context.h"
12 #include "include/err.h"
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"
23 #include <boost/bind.hpp>
24 #include <boost/optional.hpp>
26 #define dout_subsys ceph_subsys_rbd
28 #define dout_prefix *_dout << "librbd::io::ObjectRequest: " << this \
29 << " " << __func__ << ": "
36 ObjectRequest
<I
>::create_remove(I
*ictx
, const std::string
&oid
,
38 const ::SnapContext
&snapc
,
39 const ZTracer::Trace
&parent_trace
,
40 Context
*completion
) {
41 return new ObjectRemoveRequest(util::get_image_ctx(ictx
), oid
, object_no
,
42 snapc
, parent_trace
, completion
);
47 ObjectRequest
<I
>::create_truncate(I
*ictx
, const std::string
&oid
,
48 uint64_t object_no
, uint64_t object_off
,
49 const ::SnapContext
&snapc
,
50 const ZTracer::Trace
&parent_trace
,
51 Context
*completion
) {
52 return new ObjectTruncateRequest(util::get_image_ctx(ictx
), oid
, object_no
,
53 object_off
, snapc
, parent_trace
, completion
);
58 ObjectRequest
<I
>::create_trim(I
*ictx
, const std::string
&oid
,
59 uint64_t object_no
, const ::SnapContext
&snapc
,
60 bool post_object_map_update
,
61 Context
*completion
) {
62 return new ObjectTrimRequest(util::get_image_ctx(ictx
), oid
, object_no
,
63 snapc
, post_object_map_update
, completion
);
68 ObjectRequest
<I
>::create_write(I
*ictx
, const std::string
&oid
,
69 uint64_t object_no
, uint64_t object_off
,
70 const ceph::bufferlist
&data
,
71 const ::SnapContext
&snapc
, int op_flags
,
72 const ZTracer::Trace
&parent_trace
,
73 Context
*completion
) {
74 return new ObjectWriteRequest(util::get_image_ctx(ictx
), oid
, object_no
,
75 object_off
, data
, snapc
, op_flags
, parent_trace
,
81 ObjectRequest
<I
>::create_zero(I
*ictx
, const std::string
&oid
,
82 uint64_t object_no
, uint64_t object_off
,
84 const ::SnapContext
&snapc
,
85 const ZTracer::Trace
&parent_trace
,
86 Context
*completion
) {
87 return new ObjectZeroRequest(util::get_image_ctx(ictx
), oid
, object_no
,
88 object_off
, object_len
, snapc
, parent_trace
,
94 ObjectRequest
<I
>::create_writesame(I
*ictx
, const std::string
&oid
,
95 uint64_t object_no
, uint64_t object_off
,
97 const ceph::bufferlist
&data
,
98 const ::SnapContext
&snapc
, int op_flags
,
99 const ZTracer::Trace
&parent_trace
,
100 Context
*completion
) {
101 return new ObjectWriteSameRequest(util::get_image_ctx(ictx
), oid
, object_no
,
102 object_off
, object_len
, data
, snapc
,
103 op_flags
, parent_trace
, completion
);
106 template <typename I
>
108 ObjectRequest
<I
>::create_compare_and_write(I
*ictx
, const std::string
&oid
,
109 uint64_t object_no
, uint64_t object_off
,
110 const ceph::bufferlist
&cmp_data
,
111 const ceph::bufferlist
&write_data
,
112 const ::SnapContext
&snapc
,
113 uint64_t *mismatch_offset
,
115 const ZTracer::Trace
&parent_trace
,
116 Context
*completion
) {
117 return new ObjectCompareAndWriteRequest(util::get_image_ctx(ictx
), oid
,
118 object_no
, object_off
, cmp_data
,
119 write_data
, snapc
, mismatch_offset
,
120 op_flags
, parent_trace
, completion
);
123 template <typename I
>
124 ObjectRequest
<I
>::ObjectRequest(ImageCtx
*ictx
, const std::string
&oid
,
125 uint64_t objectno
, uint64_t off
,
126 uint64_t len
, librados::snap_t snap_id
,
127 bool hide_enoent
, const char *trace_name
,
128 const ZTracer::Trace
&trace
,
130 : m_ictx(ictx
), m_oid(oid
), m_object_no(objectno
), m_object_off(off
),
131 m_object_len(len
), m_snap_id(snap_id
), m_completion(completion
),
132 m_hide_enoent(hide_enoent
),
133 m_trace(util::create_trace(*ictx
, "", trace
)) {
134 if (m_trace
.valid()) {
135 m_trace
.copy_name(trace_name
+ std::string(" ") + oid
);
136 m_trace
.event("start");
139 Striper::extent_to_file(m_ictx
->cct
, &m_ictx
->layout
, m_object_no
,
140 0, m_ictx
->layout
.object_size
, m_parent_extents
);
142 RWLock::RLocker
snap_locker(m_ictx
->snap_lock
);
143 RWLock::RLocker
parent_locker(m_ictx
->parent_lock
);
144 compute_parent_extents();
147 template <typename I
>
148 void ObjectRequest
<I
>::complete(int r
)
150 if (should_complete(r
)) {
151 ldout(m_ictx
->cct
, 20) << dendl
;
152 if (m_hide_enoent
&& r
== -ENOENT
) {
155 m_completion
->complete(r
);
160 template <typename I
>
161 bool ObjectRequest
<I
>::compute_parent_extents() {
162 assert(m_ictx
->snap_lock
.is_locked());
163 assert(m_ictx
->parent_lock
.is_locked());
165 uint64_t parent_overlap
;
166 int r
= m_ictx
->get_parent_overlap(m_snap_id
, &parent_overlap
);
168 // NOTE: it's possible for a snapshot to be deleted while we are
169 // still reading from it
170 lderr(m_ictx
->cct
) << "failed to retrieve parent overlap: "
173 m_has_parent
= false;
174 m_parent_extents
.clear();
178 uint64_t object_overlap
= m_ictx
->prune_parent_extents(
179 m_parent_extents
, parent_overlap
);
180 if (object_overlap
> 0) {
181 ldout(m_ictx
->cct
, 20) << "overlap " << parent_overlap
<< " "
182 << "extents " << m_parent_extents
<< dendl
;
183 m_has_parent
= !m_parent_extents
.empty();
189 static inline bool is_copy_on_read(ImageCtx
*ictx
, librados::snap_t snap_id
) {
190 assert(ictx
->snap_lock
.is_locked());
191 return (ictx
->clone_copy_on_read
&&
192 !ictx
->read_only
&& snap_id
== CEPH_NOSNAP
&&
193 (ictx
->exclusive_lock
== nullptr ||
194 ictx
->exclusive_lock
->is_lock_owner()));
199 template <typename I
>
200 ObjectReadRequest
<I
>::ObjectReadRequest(I
*ictx
, const std::string
&oid
,
201 uint64_t objectno
, uint64_t offset
,
202 uint64_t len
, Extents
& be
,
203 librados::snap_t snap_id
, bool sparse
,
205 const ZTracer::Trace
&parent_trace
,
207 : ObjectRequest
<I
>(util::get_image_ctx(ictx
), oid
, objectno
, offset
, len
,
208 snap_id
, false, "read", parent_trace
, completion
),
209 m_buffer_extents(be
), m_tried_parent(false), m_sparse(sparse
),
210 m_op_flags(op_flags
), m_state(LIBRBD_AIO_READ_FLAT
) {
214 template <typename I
>
215 void ObjectReadRequest
<I
>::guard_read()
217 ImageCtx
*image_ctx
= this->m_ictx
;
218 RWLock::RLocker
snap_locker(image_ctx
->snap_lock
);
219 RWLock::RLocker
parent_locker(image_ctx
->parent_lock
);
221 if (this->has_parent()) {
222 ldout(image_ctx
->cct
, 20) << "guarding read" << dendl
;
223 m_state
= LIBRBD_AIO_READ_GUARD
;
227 template <typename I
>
228 bool ObjectReadRequest
<I
>::should_complete(int r
)
230 ImageCtx
*image_ctx
= this->m_ictx
;
231 ldout(image_ctx
->cct
, 20) << this->m_oid
<< " "
232 << this->m_object_off
<< "~" << this->m_object_len
233 << " r = " << r
<< dendl
;
235 bool finished
= true;
238 case LIBRBD_AIO_READ_GUARD
:
239 ldout(image_ctx
->cct
, 20) << "READ_CHECK_GUARD" << dendl
;
241 // This is the step to read from parent
242 if (!m_tried_parent
&& r
== -ENOENT
) {
244 RWLock::RLocker
snap_locker(image_ctx
->snap_lock
);
245 RWLock::RLocker
parent_locker(image_ctx
->parent_lock
);
246 if (image_ctx
->parent
== NULL
) {
247 ldout(image_ctx
->cct
, 20) << "parent is gone; do nothing" << dendl
;
251 // calculate reverse mapping onto the image
252 vector
<pair
<uint64_t,uint64_t> > parent_extents
;
253 Striper::extent_to_file(image_ctx
->cct
, &image_ctx
->layout
,
254 this->m_object_no
, this->m_object_off
,
255 this->m_object_len
, parent_extents
);
257 uint64_t parent_overlap
= 0;
258 uint64_t object_overlap
= 0;
259 r
= image_ctx
->get_parent_overlap(this->m_snap_id
, &parent_overlap
);
261 object_overlap
= image_ctx
->prune_parent_extents(parent_extents
,
265 if (object_overlap
> 0) {
266 m_tried_parent
= true;
267 if (is_copy_on_read(image_ctx
, this->m_snap_id
)) {
268 m_state
= LIBRBD_AIO_READ_COPYUP
;
271 read_from_parent(std::move(parent_extents
));
277 case LIBRBD_AIO_READ_COPYUP
:
278 ldout(image_ctx
->cct
, 20) << "READ_COPYUP" << dendl
;
279 // This is the extra step for copy-on-read: kick off an asynchronous copyup.
280 // It is different from copy-on-write as asynchronous copyup will finish
281 // by itself so state won't go back to LIBRBD_AIO_READ_GUARD.
283 assert(m_tried_parent
);
285 // If read entire object from parent success and CoR is possible, kick
286 // off a asynchronous copyup. This approach minimizes the latency
291 case LIBRBD_AIO_READ_FLAT
:
292 ldout(image_ctx
->cct
, 20) << "READ_FLAT" << dendl
;
293 // The read content should be deposit in m_read_data
296 lderr(image_ctx
->cct
) << "invalid request state: " << m_state
<< dendl
;
303 template <typename I
>
304 void ObjectReadRequest
<I
>::send() {
305 ImageCtx
*image_ctx
= this->m_ictx
;
306 ldout(image_ctx
->cct
, 20) << this->m_oid
<< " " << this->m_object_off
307 << "~" << this->m_object_len
311 RWLock::RLocker
snap_locker(image_ctx
->snap_lock
);
313 // send read request to parent if the object doesn't exist locally
314 if (image_ctx
->object_map
!= nullptr &&
315 !image_ctx
->object_map
->object_may_exist(this->m_object_no
)) {
316 image_ctx
->op_work_queue
->queue(util::create_context_callback
<
317 ObjectRequest
<I
> >(this), -ENOENT
);
322 librados::ObjectReadOperation op
;
323 int flags
= image_ctx
->get_read_flags(this->m_snap_id
);
325 op
.sparse_read(this->m_object_off
, this->m_object_len
, &m_ext_map
,
326 &m_read_data
, nullptr);
328 op
.read(this->m_object_off
, this->m_object_len
, &m_read_data
, nullptr);
330 op
.set_op_flags2(m_op_flags
);
332 librados::AioCompletion
*rados_completion
=
333 util::create_rados_callback(this);
334 int r
= image_ctx
->data_ctx
.aio_operate(
335 this->m_oid
, rados_completion
, &op
, flags
, nullptr,
336 (this->m_trace
.valid() ? this->m_trace
.get_info() : nullptr));
339 rados_completion
->release();
342 template <typename I
>
343 void ObjectReadRequest
<I
>::send_copyup()
345 ImageCtx
*image_ctx
= this->m_ictx
;
346 ldout(image_ctx
->cct
, 20) << this->m_oid
<< " " << this->m_object_off
347 << "~" << this->m_object_len
<< dendl
;
350 RWLock::RLocker
snap_locker(image_ctx
->snap_lock
);
351 RWLock::RLocker
parent_locker(image_ctx
->parent_lock
);
352 if (!this->compute_parent_extents() ||
353 (image_ctx
->exclusive_lock
!= nullptr &&
354 !image_ctx
->exclusive_lock
->is_lock_owner())) {
359 Mutex::Locker
copyup_locker(image_ctx
->copyup_list_lock
);
360 map
<uint64_t, CopyupRequest
*>::iterator it
=
361 image_ctx
->copyup_list
.find(this->m_object_no
);
362 if (it
== image_ctx
->copyup_list
.end()) {
363 // create and kick off a CopyupRequest
364 CopyupRequest
*new_req
= new CopyupRequest(
365 image_ctx
, this->m_oid
, this->m_object_no
,
366 std::move(this->m_parent_extents
), this->m_trace
);
367 this->m_parent_extents
.clear();
369 image_ctx
->copyup_list
[this->m_object_no
] = new_req
;
374 template <typename I
>
375 void ObjectReadRequest
<I
>::read_from_parent(Extents
&& parent_extents
)
377 ImageCtx
*image_ctx
= this->m_ictx
;
378 AioCompletion
*parent_completion
= AioCompletion::create_and_start
<
379 ObjectRequest
<I
> >(this, image_ctx
, AIO_TYPE_READ
);
381 ldout(image_ctx
->cct
, 20) << "parent completion " << parent_completion
382 << " extents " << parent_extents
<< dendl
;
383 ImageRequest
<>::aio_read(image_ctx
->parent
, parent_completion
,
384 std::move(parent_extents
),
385 ReadResult
{&m_read_data
}, 0, this->m_trace
);
390 AbstractObjectWriteRequest::AbstractObjectWriteRequest(ImageCtx
*ictx
,
391 const std::string
&oid
,
395 const ::SnapContext
&snapc
,
397 const char *trace_name
,
398 const ZTracer::Trace
&parent_trace
,
400 : ObjectRequest(ictx
, oid
, object_no
, object_off
, len
, CEPH_NOSNAP
,
401 hide_enoent
, trace_name
, parent_trace
, completion
),
402 m_state(LIBRBD_AIO_WRITE_FLAT
), m_snap_seq(snapc
.seq
.val
)
404 m_snaps
.insert(m_snaps
.end(), snapc
.snaps
.begin(), snapc
.snaps
.end());
407 void AbstractObjectWriteRequest::guard_write()
410 m_state
= LIBRBD_AIO_WRITE_GUARD
;
411 m_write
.assert_exists();
412 ldout(m_ictx
->cct
, 20) << "guarding write" << dendl
;
416 bool AbstractObjectWriteRequest::should_complete(int r
)
418 ldout(m_ictx
->cct
, 20) << get_op_type() << m_oid
<< " "
419 << m_object_off
<< "~" << m_object_len
420 << " r = " << r
<< dendl
;
422 bool finished
= true;
424 case LIBRBD_AIO_WRITE_PRE
:
425 ldout(m_ictx
->cct
, 20) << "WRITE_PRE" << dendl
;
434 case LIBRBD_AIO_WRITE_POST
:
435 ldout(m_ictx
->cct
, 20) << "WRITE_POST" << dendl
;
439 case LIBRBD_AIO_WRITE_GUARD
:
440 ldout(m_ictx
->cct
, 20) << "WRITE_CHECK_GUARD" << dendl
;
443 handle_write_guard();
447 // pass the error code to the finish context
448 m_state
= LIBRBD_AIO_WRITE_ERROR
;
454 finished
= send_post_object_map_update();
457 case LIBRBD_AIO_WRITE_COPYUP
:
458 ldout(m_ictx
->cct
, 20) << "WRITE_COPYUP" << dendl
;
460 m_state
= LIBRBD_AIO_WRITE_ERROR
;
464 finished
= send_post_object_map_update();
468 case LIBRBD_AIO_WRITE_FLAT
:
469 ldout(m_ictx
->cct
, 20) << "WRITE_FLAT" << dendl
;
471 finished
= send_post_object_map_update();
474 case LIBRBD_AIO_WRITE_ERROR
:
476 lderr(m_ictx
->cct
) << "WRITE_ERROR: " << cpp_strerror(r
) << dendl
;
480 lderr(m_ictx
->cct
) << "invalid request state: " << m_state
<< dendl
;
487 void AbstractObjectWriteRequest::send() {
488 ldout(m_ictx
->cct
, 20) << get_op_type() << " " << m_oid
<< " "
489 << m_object_off
<< "~" << m_object_len
<< dendl
;
491 RWLock::RLocker
snap_lock(m_ictx
->snap_lock
);
492 if (m_ictx
->object_map
== nullptr) {
493 m_object_exist
= true;
495 // should have been flushed prior to releasing lock
496 assert(m_ictx
->exclusive_lock
->is_lock_owner());
497 m_object_exist
= m_ictx
->object_map
->object_may_exist(m_object_no
);
504 void AbstractObjectWriteRequest::send_pre_object_map_update() {
505 ldout(m_ictx
->cct
, 20) << dendl
;
508 RWLock::RLocker
snap_lock(m_ictx
->snap_lock
);
509 if (m_ictx
->object_map
!= nullptr) {
511 pre_object_map_update(&new_state
);
512 RWLock::WLocker
object_map_locker(m_ictx
->object_map_lock
);
513 ldout(m_ictx
->cct
, 20) << m_oid
<< " " << m_object_off
514 << "~" << m_object_len
<< dendl
;
515 m_state
= LIBRBD_AIO_WRITE_PRE
;
517 if (m_ictx
->object_map
->aio_update
<ObjectRequest
>(
518 CEPH_NOSNAP
, m_object_no
, new_state
, {}, this->m_trace
, this)) {
527 bool AbstractObjectWriteRequest::send_post_object_map_update() {
528 ldout(m_ictx
->cct
, 20) << dendl
;
530 RWLock::RLocker
snap_locker(m_ictx
->snap_lock
);
531 if (m_ictx
->object_map
== nullptr || !post_object_map_update()) {
535 // should have been flushed prior to releasing lock
536 assert(m_ictx
->exclusive_lock
->is_lock_owner());
538 RWLock::WLocker
object_map_locker(m_ictx
->object_map_lock
);
539 ldout(m_ictx
->cct
, 20) << m_oid
<< " " << m_object_off
540 << "~" << m_object_len
<< dendl
;
541 m_state
= LIBRBD_AIO_WRITE_POST
;
543 if (m_ictx
->object_map
->aio_update
<ObjectRequest
>(
544 CEPH_NOSNAP
, m_object_no
, OBJECT_NONEXISTENT
, OBJECT_PENDING
,
545 this->m_trace
, this)) {
552 void AbstractObjectWriteRequest::send_write() {
553 ldout(m_ictx
->cct
, 20) << m_oid
<< " " << m_object_off
<< "~" << m_object_len
554 << " object exist " << m_object_exist
<< dendl
;
556 if (!m_object_exist
&& has_parent()) {
557 m_state
= LIBRBD_AIO_WRITE_GUARD
;
558 handle_write_guard();
560 send_pre_object_map_update();
564 void AbstractObjectWriteRequest::send_copyup()
566 ldout(m_ictx
->cct
, 20) << m_oid
<< " " << m_object_off
567 << "~" << m_object_len
<< dendl
;
568 m_state
= LIBRBD_AIO_WRITE_COPYUP
;
570 m_ictx
->copyup_list_lock
.Lock();
571 map
<uint64_t, CopyupRequest
*>::iterator it
=
572 m_ictx
->copyup_list
.find(m_object_no
);
573 if (it
== m_ictx
->copyup_list
.end()) {
574 CopyupRequest
*new_req
= new CopyupRequest(m_ictx
, m_oid
,
576 std::move(m_parent_extents
),
578 m_parent_extents
.clear();
580 // make sure to wait on this CopyupRequest
581 new_req
->append_request(this);
582 m_ictx
->copyup_list
[m_object_no
] = new_req
;
584 m_ictx
->copyup_list_lock
.Unlock();
587 it
->second
->append_request(this);
588 m_ictx
->copyup_list_lock
.Unlock();
591 void AbstractObjectWriteRequest::send_write_op()
593 m_state
= LIBRBD_AIO_WRITE_FLAT
;
598 add_write_ops(&m_write
, true);
599 assert(m_write
.size() != 0);
601 librados::AioCompletion
*rados_completion
=
602 util::create_rados_callback(this);
603 int r
= m_ictx
->data_ctx
.aio_operate(
604 m_oid
, rados_completion
, &m_write
, m_snap_seq
, m_snaps
,
605 (this->m_trace
.valid() ? this->m_trace
.get_info() : nullptr));
607 rados_completion
->release();
609 void AbstractObjectWriteRequest::handle_write_guard()
613 RWLock::RLocker
snap_locker(m_ictx
->snap_lock
);
614 RWLock::RLocker
parent_locker(m_ictx
->parent_lock
);
615 has_parent
= compute_parent_extents();
617 // If parent still exists, overlap might also have changed.
621 // parent may have disappeared -- send original write again
622 ldout(m_ictx
->cct
, 20) << "should_complete(" << this
623 << "): parent overlap now 0" << dendl
;
628 void ObjectWriteRequest::add_write_ops(librados::ObjectWriteOperation
*wr
,
630 RWLock::RLocker
snap_locker(m_ictx
->snap_lock
);
631 if (set_hints
&& m_ictx
->enable_alloc_hint
&&
632 (m_ictx
->object_map
== nullptr || !m_object_exist
)) {
633 wr
->set_alloc_hint(m_ictx
->get_object_size(), m_ictx
->get_object_size());
636 if (m_object_off
== 0 && m_object_len
== m_ictx
->get_object_size()) {
637 wr
->write_full(m_write_data
);
639 wr
->write(m_object_off
, m_write_data
);
641 wr
->set_op_flags2(m_op_flags
);
644 void ObjectWriteRequest::send_write() {
645 bool write_full
= (m_object_off
== 0 && m_object_len
== m_ictx
->get_object_size());
646 ldout(m_ictx
->cct
, 20) << m_oid
<< " " << m_object_off
<< "~" << m_object_len
647 << " object exist " << m_object_exist
648 << " write_full " << write_full
<< dendl
;
649 if (write_full
&& !has_parent()) {
653 AbstractObjectWriteRequest::send_write();
656 void ObjectRemoveRequest::guard_write() {
657 // do nothing to disable write guard only if deep-copyup not required
658 RWLock::RLocker
snap_locker(m_ictx
->snap_lock
);
659 if (!m_ictx
->snaps
.empty()) {
660 AbstractObjectWriteRequest::guard_write();
663 void ObjectRemoveRequest::send_write() {
664 ldout(m_ictx
->cct
, 20) << m_oid
<< " remove " << " object exist "
665 << m_object_exist
<< dendl
;
666 if (!m_object_exist
&& !has_parent()) {
667 m_state
= LIBRBD_AIO_WRITE_FLAT
;
668 Context
*ctx
= util::create_context_callback
<ObjectRequest
>(this);
669 m_ictx
->op_work_queue
->queue(ctx
, 0);
671 send_pre_object_map_update();
675 void ObjectTruncateRequest::send_write() {
676 ldout(m_ictx
->cct
, 20) << m_oid
<< " truncate " << m_object_off
677 << " object exist " << m_object_exist
<< dendl
;
678 if (!m_object_exist
&& !has_parent()) {
679 m_state
= LIBRBD_AIO_WRITE_FLAT
;
680 Context
*ctx
= util::create_context_callback
<ObjectRequest
>(this);
681 m_ictx
->op_work_queue
->queue(ctx
, 0);
683 AbstractObjectWriteRequest::send_write();
687 void ObjectZeroRequest::send_write() {
688 ldout(m_ictx
->cct
, 20) << m_oid
<< " zero " << m_object_off
<< "~"
689 << m_object_len
<< " object exist " << m_object_exist
691 if (!m_object_exist
&& !has_parent()) {
692 m_state
= LIBRBD_AIO_WRITE_FLAT
;
693 Context
*ctx
= util::create_context_callback
<ObjectRequest
>(this);
694 m_ictx
->op_work_queue
->queue(ctx
, 0);
696 AbstractObjectWriteRequest::send_write();
700 void ObjectWriteSameRequest::add_write_ops(librados::ObjectWriteOperation
*wr
,
702 RWLock::RLocker
snap_locker(m_ictx
->snap_lock
);
703 if (set_hints
&& m_ictx
->enable_alloc_hint
&&
704 (m_ictx
->object_map
== nullptr || !m_object_exist
)) {
705 wr
->set_alloc_hint(m_ictx
->get_object_size(), m_ictx
->get_object_size());
708 wr
->writesame(m_object_off
, m_object_len
, m_write_data
);
709 wr
->set_op_flags2(m_op_flags
);
712 void ObjectWriteSameRequest::send_write() {
713 bool write_full
= (m_object_off
== 0 && m_object_len
== m_ictx
->get_object_size());
714 ldout(m_ictx
->cct
, 20) << m_oid
<< " " << m_object_off
<< "~" << m_object_len
715 << " write_full " << write_full
<< dendl
;
716 if (write_full
&& !has_parent()) {
720 AbstractObjectWriteRequest::send_write();
723 void ObjectCompareAndWriteRequest::add_write_ops(librados::ObjectWriteOperation
*wr
,
725 RWLock::RLocker
snap_locker(m_ictx
->snap_lock
);
727 if (set_hints
&& m_ictx
->enable_alloc_hint
&&
728 (m_ictx
->object_map
== nullptr || !m_object_exist
)) {
729 wr
->set_alloc_hint(m_ictx
->get_object_size(), m_ictx
->get_object_size());
733 wr
->cmpext(m_object_off
, m_cmp_bl
, nullptr);
735 if (m_object_off
== 0 && m_object_len
== m_ictx
->get_object_size()) {
736 wr
->write_full(m_write_bl
);
738 wr
->write(m_object_off
, m_write_bl
);
740 wr
->set_op_flags2(m_op_flags
);
743 void ObjectCompareAndWriteRequest::send_write() {
744 bool write_full
= (m_object_off
== 0 &&
745 m_object_len
== m_ictx
->get_object_size());
746 ldout(m_ictx
->cct
, 20) << "send_write " << this << " " << m_oid
<< " "
747 << m_object_off
<< "~" << m_object_len
748 << " object exist " << m_object_exist
749 << " write_full " << write_full
<< dendl
;
750 if (write_full
&& !has_parent()) {
754 AbstractObjectWriteRequest::send_write();
757 void ObjectCompareAndWriteRequest::complete(int r
)
759 if (should_complete(r
)) {
760 ImageCtx
*image_ctx
= this->m_ictx
;
761 ldout(m_ictx
->cct
, 20) << "complete " << this << dendl
;
763 if (this->m_hide_enoent
&& r
== -ENOENT
) {
767 vector
<pair
<uint64_t,uint64_t> > file_extents
;
768 if (r
<= -MAX_ERRNO
) {
769 // object extent compare mismatch
770 uint64_t offset
= -MAX_ERRNO
- r
;
771 Striper::extent_to_file(image_ctx
->cct
, &image_ctx
->layout
,
772 this->m_object_no
, offset
, this->m_object_len
,
775 assert(file_extents
.size() == 1);
777 uint64_t mismatch_offset
= file_extents
[0].first
;
778 if (this->m_mismatch_offset
)
779 *this->m_mismatch_offset
= mismatch_offset
;
783 //compare and write object extent error
784 m_completion
->complete(r
);
790 } // namespace librbd
792 template class librbd::io::ObjectRequest
<librbd::ImageCtx
>;
793 template class librbd::io::ObjectReadRequest
<librbd::ImageCtx
>;