--- /dev/null
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+
+#include "librbd/io/AioCompletion.h"
+#include <errno.h>
+
+#include "common/ceph_context.h"
+#include "common/dout.h"
+#include "common/errno.h"
+#include "common/perf_counters.h"
+#include "common/WorkQueue.h"
+
+#include "librbd/ImageCtx.h"
+#include "librbd/internal.h"
+
+#include "librbd/Journal.h"
+
+#ifdef WITH_LTTNG
+#include "tracing/librbd.h"
+#else
+#define tracepoint(...)
+#endif
+
+#define dout_subsys ceph_subsys_rbd
+#undef dout_prefix
+#define dout_prefix *_dout << "librbd::io::AioCompletion: " << this \
+ << " " << __func__ << ": "
+
+namespace librbd {
+namespace io {
+
+int AioCompletion::wait_for_complete() {
+ tracepoint(librbd, aio_wait_for_complete_enter, this);
+ lock.Lock();
+ while (state != AIO_STATE_COMPLETE)
+ cond.Wait(lock);
+ lock.Unlock();
+ tracepoint(librbd, aio_wait_for_complete_exit, 0);
+ return 0;
+}
+
+void AioCompletion::finalize(ssize_t rval)
+{
+ assert(lock.is_locked());
+ assert(ictx != nullptr);
+ CephContext *cct = ictx->cct;
+
+ ldout(cct, 20) << "r=" << rval << dendl;
+ if (rval >= 0 && aio_type == AIO_TYPE_READ) {
+ read_result.assemble_result(cct);
+ }
+}
+
+void AioCompletion::complete() {
+ assert(lock.is_locked());
+ assert(ictx != nullptr);
+ CephContext *cct = ictx->cct;
+
+ tracepoint(librbd, aio_complete_enter, this, rval);
+ utime_t elapsed;
+ elapsed = ceph_clock_now() - start_time;
+ switch (aio_type) {
+ case AIO_TYPE_GENERIC:
+ case AIO_TYPE_OPEN:
+ case AIO_TYPE_CLOSE:
+ break;
+ case AIO_TYPE_READ:
+ ictx->perfcounter->tinc(l_librbd_rd_latency, elapsed); break;
+ case AIO_TYPE_WRITE:
+ ictx->perfcounter->tinc(l_librbd_wr_latency, elapsed); break;
+ case AIO_TYPE_DISCARD:
+ ictx->perfcounter->tinc(l_librbd_discard_latency, elapsed); break;
+ case AIO_TYPE_FLUSH:
+ ictx->perfcounter->tinc(l_librbd_aio_flush_latency, elapsed); break;
+ case AIO_TYPE_WRITESAME:
+ ictx->perfcounter->tinc(l_librbd_ws_latency, elapsed); break;
+ case AIO_TYPE_COMPARE_AND_WRITE:
+ ictx->perfcounter->tinc(l_librbd_cmp_latency, elapsed); break;
+ default:
+ lderr(cct) << "completed invalid aio_type: " << aio_type << dendl;
+ break;
+ }
+
+ // inform the journal that the op has successfully committed
+ if (journal_tid != 0) {
+ assert(ictx->journal != NULL);
+ ictx->journal->commit_io_event(journal_tid, rval);
+ }
+
+ state = AIO_STATE_CALLBACK;
+ if (complete_cb) {
+ lock.Unlock();
+ complete_cb(rbd_comp, complete_arg);
+ lock.Lock();
+ }
+
+ if (ictx && event_notify && ictx->event_socket.is_valid()) {
+ ictx->completed_reqs_lock.Lock();
+ ictx->completed_reqs.push_back(&m_xlist_item);
+ ictx->completed_reqs_lock.Unlock();
+ ictx->event_socket.notify();
+ }
+
+ state = AIO_STATE_COMPLETE;
+ cond.Signal();
+
+ // note: possible for image to be closed after op marked finished
+ if (async_op.started()) {
+ async_op.finish_op();
+ }
+ tracepoint(librbd, aio_complete_exit);
+}
+
+void AioCompletion::init_time(ImageCtx *i, aio_type_t t) {
+ Mutex::Locker locker(lock);
+ if (ictx == nullptr) {
+ ictx = i;
+ aio_type = t;
+ start_time = ceph_clock_now();
+ }
+}
+
+void AioCompletion::start_op(bool ignore_type) {
+ Mutex::Locker locker(lock);
+ assert(ictx != nullptr);
+ assert(!async_op.started());
+ if (state == AIO_STATE_PENDING &&
+ (ignore_type || aio_type != AIO_TYPE_FLUSH)) {
+ async_op.start_op(*ictx);
+ }
+}
+
+void AioCompletion::fail(int r)
+{
+ lock.Lock();
+ assert(ictx != nullptr);
+ CephContext *cct = ictx->cct;
+
+ lderr(cct) << cpp_strerror(r) << dendl;
+ assert(pending_count == 0);
+ rval = r;
+ complete();
+ put_unlock();
+}
+
+void AioCompletion::set_request_count(uint32_t count) {
+ lock.Lock();
+ assert(ictx != nullptr);
+ CephContext *cct = ictx->cct;
+
+ ldout(cct, 20) << "pending=" << count << dendl;
+ assert(pending_count == 0);
+ pending_count = count;
+ lock.Unlock();
+
+ // if no pending requests, completion will fire now
+ unblock();
+}
+
+void AioCompletion::complete_request(ssize_t r)
+{
+ lock.Lock();
+ assert(ictx != nullptr);
+ CephContext *cct = ictx->cct;
+
+ if (rval >= 0) {
+ if (r < 0 && r != -EEXIST)
+ rval = r;
+ else if (r > 0)
+ rval += r;
+ }
+ assert(pending_count);
+ int count = --pending_count;
+
+ ldout(cct, 20) << "cb=" << complete_cb << ", "
+ << "pending=" << pending_count << dendl;
+ if (!count && blockers == 0) {
+ finalize(rval);
+ complete();
+ }
+ put_unlock();
+}
+
+void AioCompletion::associate_journal_event(uint64_t tid) {
+ Mutex::Locker l(lock);
+ assert(state == AIO_STATE_PENDING);
+ journal_tid = tid;
+}
+
+bool AioCompletion::is_complete() {
+ tracepoint(librbd, aio_is_complete_enter, this);
+ bool done;
+ {
+ Mutex::Locker l(lock);
+ done = this->state == AIO_STATE_COMPLETE;
+ }
+ tracepoint(librbd, aio_is_complete_exit, done);
+ return done;
+}
+
+ssize_t AioCompletion::get_return_value() {
+ tracepoint(librbd, aio_get_return_value_enter, this);
+ lock.Lock();
+ ssize_t r = rval;
+ lock.Unlock();
+ tracepoint(librbd, aio_get_return_value_exit, r);
+ return r;
+}
+
+} // namespace io
+} // namespace librbd