]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
librados/asio: clear cancellation slot in associated executor 68873/head
authorCasey Bodley <cbodley@redhat.com>
Tue, 12 May 2026 18:58:16 +0000 (14:58 -0400)
committerCasey Bodley <cbodley@redhat.com>
Mon, 18 May 2026 17:31:26 +0000 (13:31 -0400)
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 <cbodley@redhat.com>
src/librados/librados_asio.h

index 077ab79b141bf6e04ba69dda51496fc48e1db72b..19ab0120a666570f4af58632023e0df7689063cd 100644 (file)
@@ -85,6 +85,8 @@ struct Invoker<void> {
   }
 };
 
+// handler wrapper that clears the handler's associated cancellation slot
+// before invoking it
 template <typename Handler>
 struct AsyncHandler {
   Handler handler;
@@ -93,6 +95,10 @@ struct AsyncHandler {
 
   template <typename ...Args>
   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>(args)...);
   }
@@ -136,7 +142,6 @@ struct AsyncOp : Invoker<Result> {
     auto p = std::unique_ptr<Completion>{static_cast<Completion*>(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;