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=b5ade012340a83fb1874526b850ec5d67d9d2a6d;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 (cherry picked from commit d91bd72f1b87a31283468fbf171159074c187685) --- diff --git a/src/librados/librados_asio.h b/src/librados/librados_asio.h index 95dec034a6a..ee7328445f3 100644 --- a/src/librados/librados_asio.h +++ b/src/librados/librados_asio.h @@ -84,6 +84,8 @@ struct Invoker { } }; +// handler wrapper that clears the handler's associated cancellation slot +// before invoking it template struct AsyncHandler { Handler handler; @@ -92,6 +94,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)...); } @@ -135,7 +141,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;