From: Shilpa Jagannath Date: Fri, 5 Jun 2026 18:42:35 +0000 (-0400) Subject: common/async: async_cond::notify/cancel must post to handler's associated executor X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=1c287c88688b157fa323eb910e2d10ae82a6e2c0;p=ceph.git common/async: async_cond::notify/cancel must post to handler's associated executor RGWDeleteMultiObj spawns child coroutines via spawn_throttle to delete objects in parallel. each child coroutine carries the connection strand as its associated executor, serializing concurrent operations on shared state like the response formatter and ops_log_entries. but in multisite env, concurrent deletions in the same bucket shard contend on async_cond in RGWDataChangesLog::add_entry(). when notify() fires, waiting coroutines resume on the raw io_context executor instead of their connection strand, breaking the serialization that prevents data races in send_partial_response() any_completion_handler doesn't support post(). so post() to the default executor and dispatch to the associated executor from there Signed-off-by: Shilpa Jagannath (cherry picked from commit 04aceefad0ef2b0186b0854ae28b4fbc4ffa51c3) --- diff --git a/src/common/async/async_cond.h b/src/common/async/async_cond.h index 8f6ccd632a3..b27fb6dcb94 100644 --- a/src/common/async/async_cond.h +++ b/src/common/async/async_cond.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -55,8 +56,8 @@ class async_cond : public service_list_base_hook { std::mutex m; std::vector, std::unique_lock*>> handlers; + boost::asio::any_completion_handler, + std::unique_lock*>> handlers; void service_shutdown() { std::unique_lock l(m); @@ -132,12 +133,13 @@ public: handlers.resize(0); l.unlock(); for (auto&& [handler, lock] : workhandlers) { + auto ex = asio::get_associated_executor(handler, executor); asio::post(executor, - [handler = std::move(handler), lock = lock]() mutable { - lock->lock(); - std::move(handler)(sys::error_code{}); - }); - + asio::bind_executor(ex, + [handler = std::move(handler), lock = lock]() mutable { + lock->lock(); + std::move(handler)(sys::error_code{}); + })); } } } @@ -154,12 +156,13 @@ public: handlers.resize(0); l.unlock(); for (auto&& [handler, lock] : workhandlers) { + auto ex = asio::get_associated_executor(handler, executor); asio::post(executor, - [handler = std::move(handler), lock = lock]() mutable { - lock->lock(); - std::move(handler)(asio::error::operation_aborted); - }); - + asio::bind_executor(ex, + [handler = std::move(handler), lock = lock]() mutable { + lock->lock(); + std::move(handler)(asio::error::operation_aborted); + })); } } }