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/AioCompletion.h"
7 #include "common/ceph_context.h"
8 #include "common/dout.h"
9 #include "common/errno.h"
10 #include "common/perf_counters.h"
11 #include "common/WorkQueue.h"
13 #include "librbd/ImageCtx.h"
14 #include "librbd/internal.h"
15 #include "librbd/Journal.h"
16 #include "librbd/Types.h"
19 #include "tracing/librbd.h"
21 #define tracepoint(...)
24 #define dout_subsys ceph_subsys_rbd
26 #define dout_prefix *_dout << "librbd::io::AioCompletion: " << this \
27 << " " << __func__ << ": "
32 int AioCompletion::wait_for_complete() {
33 tracepoint(librbd
, aio_wait_for_complete_enter
, this);
35 while (state
!= AIO_STATE_COMPLETE
)
38 tracepoint(librbd
, aio_wait_for_complete_exit
, 0);
42 void AioCompletion::finalize(ssize_t rval
)
44 ceph_assert(lock
.is_locked());
45 ceph_assert(ictx
!= nullptr);
46 CephContext
*cct
= ictx
->cct
;
48 ldout(cct
, 20) << "r=" << rval
<< dendl
;
49 if (rval
>= 0 && aio_type
== AIO_TYPE_READ
) {
50 read_result
.assemble_result(cct
);
54 void AioCompletion::complete() {
55 ceph_assert(lock
.is_locked());
56 ceph_assert(ictx
!= nullptr);
57 CephContext
*cct
= ictx
->cct
;
59 tracepoint(librbd
, aio_complete_enter
, this, rval
);
60 if (ictx
->perfcounter
!= nullptr) {
61 ceph::timespan elapsed
= coarse_mono_clock::now() - start_time
;
63 case AIO_TYPE_GENERIC
:
68 ictx
->perfcounter
->tinc(l_librbd_rd_latency
, elapsed
); break;
70 ictx
->perfcounter
->tinc(l_librbd_wr_latency
, elapsed
); break;
71 case AIO_TYPE_DISCARD
:
72 ictx
->perfcounter
->tinc(l_librbd_discard_latency
, elapsed
); break;
74 ictx
->perfcounter
->tinc(l_librbd_flush_latency
, elapsed
); break;
75 case AIO_TYPE_WRITESAME
:
76 ictx
->perfcounter
->tinc(l_librbd_ws_latency
, elapsed
); break;
77 case AIO_TYPE_COMPARE_AND_WRITE
:
78 ictx
->perfcounter
->tinc(l_librbd_cmp_latency
, elapsed
); break;
80 lderr(cct
) << "completed invalid aio_type: " << aio_type
<< dendl
;
85 if ((aio_type
== AIO_TYPE_CLOSE
) ||
86 (aio_type
== AIO_TYPE_OPEN
&& rval
< 0)) {
87 // must destroy ImageCtx prior to invoking callback
92 state
= AIO_STATE_CALLBACK
;
95 complete_cb(rbd_comp
, complete_arg
);
99 if (ictx
!= nullptr && event_notify
&& ictx
->event_socket
.is_valid()) {
100 ictx
->completed_reqs_lock
.Lock();
101 ictx
->completed_reqs
.push_back(&m_xlist_item
);
102 ictx
->completed_reqs_lock
.Unlock();
103 ictx
->event_socket
.notify();
106 state
= AIO_STATE_COMPLETE
;
109 // note: possible for image to be closed after op marked finished
110 if (async_op
.started()) {
111 async_op
.finish_op();
113 tracepoint(librbd
, aio_complete_exit
);
116 void AioCompletion::init_time(ImageCtx
*i
, aio_type_t t
) {
117 Mutex::Locker
locker(lock
);
118 if (ictx
== nullptr) {
121 start_time
= coarse_mono_clock::now();
125 void AioCompletion::start_op(bool ignore_type
) {
126 Mutex::Locker
locker(lock
);
127 ceph_assert(ictx
!= nullptr);
128 ceph_assert(!async_op
.started());
130 if (aio_type
== AIO_TYPE_OPEN
|| aio_type
== AIO_TYPE_CLOSE
) {
131 // no need to track async open/close operations
135 if (state
== AIO_STATE_PENDING
&&
136 (ignore_type
|| aio_type
!= AIO_TYPE_FLUSH
)) {
137 async_op
.start_op(*ictx
);
141 void AioCompletion::fail(int r
)
144 ceph_assert(ictx
!= nullptr);
145 CephContext
*cct
= ictx
->cct
;
147 lderr(cct
) << cpp_strerror(r
) << dendl
;
148 ceph_assert(pending_count
== 0);
154 void AioCompletion::set_request_count(uint32_t count
) {
156 ceph_assert(ictx
!= nullptr);
157 CephContext
*cct
= ictx
->cct
;
159 ldout(cct
, 20) << "pending=" << count
<< dendl
;
160 ceph_assert(pending_count
== 0);
163 pending_count
= count
;
169 // ensure completion fires in clean lock context
170 ictx
->op_work_queue
->queue(new C_AioRequest(this), 0);
174 void AioCompletion::complete_request(ssize_t r
)
177 ceph_assert(ictx
!= nullptr);
178 CephContext
*cct
= ictx
->cct
;
181 if (r
< 0 && r
!= -EEXIST
)
186 ceph_assert(pending_count
);
187 int count
= --pending_count
;
189 ldout(cct
, 20) << "cb=" << complete_cb
<< ", "
190 << "pending=" << pending_count
<< dendl
;
198 bool AioCompletion::is_complete() {
199 tracepoint(librbd
, aio_is_complete_enter
, this);
202 Mutex::Locker
l(lock
);
203 done
= this->state
== AIO_STATE_COMPLETE
;
205 tracepoint(librbd
, aio_is_complete_exit
, done
);
209 ssize_t
AioCompletion::get_return_value() {
210 tracepoint(librbd
, aio_get_return_value_enter
, this);
214 tracepoint(librbd
, aio_get_return_value_exit
, r
);
219 } // namespace librbd