From cb615de539e10e746b0a891dfb56ab0cfbedeb9b Mon Sep 17 00:00:00 2001 From: "Adam C. Emerson" Date: Thu, 5 Mar 2026 19:53:17 -0500 Subject: [PATCH] neorados: Go through linger_cancel on `io_context` shutdown Rather than just dropping the reference, clean up the linger operation properly within Objecter. Also, clear out handlers before relinquishing reference to avoid use-after-free. Fixes: https://tracker.ceph.com/issues/75164 Signed-off-by: Adam C. Emerson (cherry picked from commit f5affe06676bec2f32f856bce85b5d78932d807f) Conflicts: qa/workunits/rados/test.sh - Just drop the `watch_leak` test on teuthology since it's of marginal utility and not worth backporting all of . Fixes: https://tracker.ceph.com/issues/76434 Signed-off-by: Adam C. Emerson --- src/neorados/RADOS.cc | 19 +++++++--- src/test/neorados/CMakeLists.txt | 7 ++++ src/test/neorados/leak_watch_notify.cc | 50 ++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 src/test/neorados/leak_watch_notify.cc diff --git a/src/neorados/RADOS.cc b/src/neorados/RADOS.cc index 8959754c155..6aeaddbf7df 100644 --- a/src/neorados/RADOS.cc +++ b/src/neorados/RADOS.cc @@ -1408,12 +1408,23 @@ class Notifier : public async::service_list_base_hook { std::shared_ptr neoref; void service_shutdown() { - if (neoref) { - neoref = nullptr; - } - linger_op.reset(); + // Ensure neorados object and operation live to the end of the + // function. + auto localop = std::move(linger_op); + [[maybe_unused]] auto localneo = std::move(neoref); std::unique_lock l(m); handlers.clear(); + l.unlock(); + if (localop) { + // We are being taken down and will execute no more + // handlers. Call `linger_cancel` to clean up properly in + // Objecter. (It doesn't call out to the OSD or anything.) + // + // Removal and decrement are guarded by `linger_op->canceled` + // so there's no risk of an underflow. + localop->objecter->linger_cancel(localop.get()); + } + // The Notifier object is freed by the `linger_cancel` above. } public: diff --git a/src/test/neorados/CMakeLists.txt b/src/test/neorados/CMakeLists.txt index 968ef609cdc..432b0336425 100644 --- a/src/test/neorados/CMakeLists.txt +++ b/src/test/neorados/CMakeLists.txt @@ -233,3 +233,10 @@ target_link_libraries(ceph_test_neorados_watch_notify install(TARGETS ceph_test_neorados_watch_notify DESTINATION ${CMAKE_INSTALL_BINDIR}) + +add_executable(ceph_test_neorados_leak_watch_notify leak_watch_notify.cc) +target_link_libraries(ceph_test_neorados_leak_watch_notify global libneorados + neoradostest-support ${unittest_libs}) +install(TARGETS + ceph_test_neorados_leak_watch_notify + DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/test/neorados/leak_watch_notify.cc b/src/test/neorados/leak_watch_notify.cc new file mode 100644 index 00000000000..407e622b595 --- /dev/null +++ b/src/test/neorados/leak_watch_notify.cc @@ -0,0 +1,50 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:nil -*- +// vim: ts=8 sw=2 sts=2 expandtab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2026 Contributors to the Ceph Project + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include +#include + +#include +#include + +#include "include/neorados/RADOS.hpp" + +#include "common_tests.h" + +namespace asio = boost::asio; + +using boost::system::error_code; + +// Intentionally get a watch and don't unwatch it to make sure we call +// `linger_cancel` and don't leak. + +int main() +{ + asio::io_context c; + std::string_view oid = "obj"; + + std::optional rados; + neorados::IOContext pool; + neorados::RADOS::Builder{}.build(c, [&](error_code ec, neorados::RADOS r_) { + rados = std::move(r_); + create_pool(*rados, get_temp_pool_name(), + [&](error_code ec, int64_t poolid) { + pool.set_pool(poolid); + rados->watch(oid, pool, [&](error_code, std::uint64_t cookie) { + std::cout << "Got watch: " << cookie << std::endl; + }); + }); + }); + c.run(); +} -- 2.47.3