From 40d86efb4e10d3ac35bc77664a9bc2fc13797ace Mon Sep 17 00:00:00 2001 From: "randomizedcoder dave.seddon.ca@gmail.com" Date: Thu, 29 Oct 2026 09:32:35 -0700 Subject: [PATCH] Wait for route RCU callbacks in homa_peer_free_net homa_peer_free_net releases each route in the namespace with call_rcu(homa_route_free), and homa_route_free dereferences route->key.hnet to find the peertab. But hnet is the pernet data for the namespace, which cleanup_net frees right after the exit methods return (its rcu_barrier comes later). A callback that runs after that reads freed memory. Found by deleting network namespaces that had carried Homa traffic, in a VM: with init_on_free=1 every run oopsed in homa_route_free (6.12 and 7.3); without it, 3 of 8 runs on 7.3 hit a general protection fault there under load. Co-Authored-By: Claude Opus 5.5 --- homa_peer.c | 5 +++++ test/unit_homa_peer.c | 15 +++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/homa_peer.c b/homa_peer.c index 1e1f38a5..73e09c4d 100644 --- a/homa_peer.c +++ b/homa_peer.c @@ -172,6 +172,11 @@ void homa_peer_free_net(struct homa_net *hnet) WARN(hnet->num_routes != 0, "%s ended up with hnet->num_routes %d", __func__, hnet->num_routes); spin_unlock_bh(&peertab->lock); + + /* homa_route_free uses hnet, which will be freed as soon as we + * return, so wait for the callbacks queued above. + */ + rcu_barrier(); } /** diff --git a/test/unit_homa_peer.c b/test/unit_homa_peer.c index a8668116..a09b24b9 100644 --- a/test/unit_homa_peer.c +++ b/test/unit_homa_peer.c @@ -151,6 +151,21 @@ TEST_F(homa_peer, homa_peer_free_net__basics) unit_sock_destroy(&hsk2); } +TEST_F(homa_peer, homa_peer_free_net__wait_for_rcu_callbacks) +{ + /* The homa_net is freed as soon as homa_peer_free_net returns, so + * the homa_route_free callbacks (which use it) must have finished. + */ + struct homa_route *route; + + route = homa_route_get(&self->hsk, ip1111); + homa_route_release(route); + EXPECT_EQ(1, unit_count_peers(&self->homa)); + + homa_peer_free_net(self->hnet); + EXPECT_EQ(0, unit_count_peers(&self->homa)); +} + TEST_F(homa_peer, homa_route_delete_fn) { struct homa_route *route;