From 1d6e6b821e56235ffb0f6145160ac7beef67ad27 Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Tue, 2 Jun 2026 15:48:41 +0800 Subject: [PATCH] rgw/posix: start the Inotify thread last, after the rest is built f62e811f9ef fixed the wfd/efd init-order race but missed a sibling: thrd was still declared before map_mutex, the watch maps and the shutdown flag. Members come up in declaration order, so building thrd kicks off ev_loop() while those are still uninitialized. That is bad news, because ev_loop() reads shutdown and, when an event arrives, locks map_mutex and pokes at the maps. Doing any of that before they are constructed is undefined behavior: reading the shutdown atomic before its initializer has even stored false, or locking a std::mutex that does not exist yet. Making shutdown a std::atomic made concurrent access well-defined, but that does not help if the load happens before the object is constructed. So just declare thrd last, and the thread will not start until everything it touches is ready. wfd/efd stay ahead of it, so the earlier fix still holds. helgrind caught the shutdown read in ev_loop() racing its own initializer in the constructor. Fixes: https://tracker.ceph.com/issues/75601 Signed-off-by: Kefu Chai --- src/rgw/driver/posix/notify.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/rgw/driver/posix/notify.h b/src/rgw/driver/posix/notify.h index bdfd5ec582a..99c2397d483 100644 --- a/src/rgw/driver/posix/notify.h +++ b/src/rgw/driver/posix/notify.h @@ -112,11 +112,13 @@ namespace file::listing { using wd_remove_map_t = ankerl::unordered_dense::map; int wfd, efd; - std::thread thrd; std::mutex map_mutex; // protects wd_callback_map and wd_remove_map wd_callback_map_t wd_callback_map; wd_remove_map_t wd_remove_map; std::atomic shutdown{false}; + /* must be last: starting the thread (ev_loop) reaches every member + * above, which are constructed in declaration order */ + std::thread thrd; class AlignedBuf { -- 2.47.3