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;