From: Casey Bodley Date: Tue, 12 May 2026 18:58:16 +0000 (-0400) Subject: librados/asio: clear cancellation slot in associated executor X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=d91bd72f1b87a31283468fbf171159074c187685;p=ceph.git librados/asio: clear cancellation slot in associated executor the librados callback function `AsyncOp::aio_dispatch()` runs on Objecter's finisher strand executor, and dispatches the completion handler to its associated executor asio cancellation is not thread-safe, so should be synchronized on that associated executor. move the call to `slot.clear()` from that librados callback into the AsyncHandler wrapper so it doesn't run until we've switched to the correct executor because our `op_cancellation` handler depends on an `AioCompletion` pointer, we have to clear the cancellation slot before that `AioCompletion` lifetime ends Fixes: https://tracker.ceph.com/issues/73475 Signed-off-by: Casey Bodley --- diff --git a/src/librados/librados_asio.h b/src/librados/librados_asio.h index 077ab79b141b..19ab0120a666 100644 --- a/src/librados/librados_asio.h +++ b/src/librados/librados_asio.h @@ -85,6 +85,8 @@ struct Invoker { } }; +// handler wrapper that clears the handler's associated cancellation slot +// before invoking it template struct AsyncHandler { Handler handler; @@ -93,6 +95,10 @@ struct AsyncHandler { template void operator()(unique_aio_completion_ptr aio_completion, Args&& ...args) { + // the cancellation handler refers to the AioCompletion, so needs to be + // cleared before the AioCompletion is destroyed + auto slot = boost::asio::get_associated_cancellation_slot(handler); + slot.clear(); aio_completion.reset(); std::move(handler)(std::forward(args)...); } @@ -136,7 +142,6 @@ struct AsyncOp : Invoker { auto p = std::unique_ptr{static_cast(arg)}; // move result out of Completion memory being freed auto op = std::move(p->user_data); - op.slot.clear(); // clear our cancellation handler // access AioCompletionImpl directly to avoid locking const librados::AioCompletionImpl* pc = op.aio_completion->pc; const int ret = pc->rval;