From: Jason Dillaman Date: Tue, 30 Apr 2019 16:56:08 +0000 (-0400) Subject: librbd: allow AioCompletion objects to be blocked X-Git-Tag: v15.1.0~2767^2~3 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=285677761389ecc51f044afce5044467539179e6;p=ceph.git librbd: allow AioCompletion objects to be blocked This will be used when user-provided memory is wrapped into a ceph::buffer::raw pointer to prevent its release prior to the drop of its last reference internally. Signed-off-by: Jason Dillaman --- diff --git a/src/librbd/io/AioCompletion.cc b/src/librbd/io/AioCompletion.cc index 610435aceefe..011b005dfd4a 100644 --- a/src/librbd/io/AioCompletion.cc +++ b/src/librbd/io/AioCompletion.cc @@ -140,32 +140,64 @@ void AioCompletion::start_op() { async_op.start_op(*ictx); } +void AioCompletion::queue_complete() { + uint32_t zero = 0; + pending_count.compare_exchange_strong(zero, 1); + ceph_assert(zero == 0); + + // ensure completion fires in clean lock context + ictx->op_work_queue->queue(new C_AioRequest(this), 0); +} + +void AioCompletion::block(CephContext* cct) { + ldout(cct, 20) << dendl; + ceph_assert(!was_armed); + + get(); + ++pending_count; +} + +void AioCompletion::unblock(CephContext* cct) { + ldout(cct, 20) << dendl; + ceph_assert(was_armed); + + uint32_t previous_pending_count = pending_count--; + ceph_assert(previous_pending_count > 0); + + if (previous_pending_count == 1) { + queue_complete(); + } + put(); +} + void AioCompletion::fail(int r) { ceph_assert(ictx != nullptr); CephContext *cct = ictx->cct; - lderr(cct) << cpp_strerror(r) << dendl; - uint32_t previous_pending_count = pending_count.exchange(1); - ceph_assert(previous_pending_count == 0); - // ensure completion fires in clean lock context - ictx->op_work_queue->queue(new C_AioRequest(this), r); + ceph_assert(!was_armed); + was_armed = true; + + error_rval = r; + + uint32_t previous_pending_count = pending_count.load(); + if (previous_pending_count == 0) { + queue_complete(); + } } void AioCompletion::set_request_count(uint32_t count) { ceph_assert(ictx != nullptr); CephContext *cct = ictx->cct; - uint32_t previous_pending_count = pending_count.exchange( - count == 0 ? 1 : count); - ceph_assert(previous_pending_count == 0); + ceph_assert(!was_armed); + was_armed = true; ldout(cct, 20) << "pending=" << count << dendl; - if (count == 0) { - // ensure completion fires in clean lock context - ictx->op_work_queue->queue(new C_AioRequest(this), 0); - return; + uint32_t previous_pending_count = pending_count.fetch_add(count); + if (previous_pending_count == 0 && count == 0) { + queue_complete(); } } diff --git a/src/librbd/io/AioCompletion.h b/src/librbd/io/AioCompletion.h index 46f2bd0b0216..551596a0de83 100644 --- a/src/librbd/io/AioCompletion.h +++ b/src/librbd/io/AioCompletion.h @@ -57,7 +57,7 @@ struct AioCompletion { std::atomic rval{0}; std::atomic error_rval{0}; std::atomic ref{1}; - std::atomic pending_count{0}; ///< number of requests + std::atomic pending_count{0}; ///< number of requests/blocks std::atomic released{false}; ImageCtx *ictx = nullptr; @@ -69,6 +69,7 @@ struct AioCompletion { AsyncOperation async_op; bool event_notify = false; + bool was_armed = false; template static void callback_adapter(completion_t cb, void *arg) { @@ -122,6 +123,9 @@ struct AioCompletion { return async_op.started(); } + void block(CephContext* cct); + void unblock(CephContext* cct); + void init_time(ImageCtx *i, aio_type_t t); void start_op(); void fail(int r); @@ -169,6 +173,10 @@ struct AioCompletion { void *get_arg() { return complete_arg; } + +private: + void queue_complete(); + }; class C_AioRequest : public Context {