mirror of
https://github.com/openwrt/openwrt.git
synced 2026-10-13 21:58:06 +04:00
realtek: l3: free the routes and the hash table on remove
Remove stopped the notifiers and drained the driver's queue, but only released the IPv6 FIB entries the routes held: the route objects, their source lists and the hash table stayed allocated. The table's resize work is not on the driver's queue either, so one still pending could run after unbind had freed the controller. Free every route with the helper a delete ends with, under rtnl as its other callers hold it, and destroy the hash table, which also cancels or waits for its resize work. The hardware rows stay as they were, as before; the kernel's IPv6 routes lose their offload mark. Probe now cleans up the same way when the netevent notifier cannot be registered, after the catch-all rows are already in. Tested on a Hasivo S1100W-8XGT-SE (RTL9303) with L3 offload enabled, unbinding the switch driver with 300 routes programmed (200 IPv4 prefixes, 50 IPv4 host routes, 50 IPv6 prefixes; 321 driver rows with the catch-all ones). Unreclaimable slab memory went down by 100 kB across the unbind without this change and by 224 kB with it; the 50 IPv6 routes kept their offload mark without it and lost it with it. No warning or oops either way. Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Gennaro Cimmino <gcimmino@rayonra.net> Link: https://github.com/openwrt/openwrt/pull/25622 Signed-off-by: Markus Stockhausen <markus.stockhausen@gmx.de>
This commit is contained in:
1 parent
f149687bbd
commit
8d523002da
1 file changed
+9
-8
@@ -3636,7 +3636,7 @@ static const struct of_device_id otto_l3_of_ids[] = {
|
||||
void otto_l3_remove(struct rtl838x_switch_priv *priv)
|
||||
{
|
||||
struct otto_l3_ctrl *ctrl = priv->l3_ctrl;
|
||||
struct otto_l3_route *r;
|
||||
struct otto_l3_route *r, *tmp;
|
||||
|
||||
/* A replay would register the FIB notifier again */
|
||||
disable_delayed_work_sync(&ctrl->resync_work);
|
||||
@@ -3658,14 +3658,14 @@ void otto_l3_remove(struct rtl838x_switch_priv *priv)
|
||||
flush_workqueue(priv->wq);
|
||||
|
||||
/* Nothing takes a route out now, and a FIB entry one still names would
|
||||
* be kept alive by it.
|
||||
* be kept alive by it. Destroying the hash table also waits for the
|
||||
* resize work it runs on its own.
|
||||
*/
|
||||
list_for_each_entry(r, &ctrl->routes_list, list) {
|
||||
if (!IS_REACHABLE(CONFIG_IPV6) || !r->f6i)
|
||||
continue;
|
||||
fib6_info_release(r->f6i);
|
||||
r->f6i = NULL;
|
||||
}
|
||||
rtnl_lock();
|
||||
list_for_each_entry_safe(r, tmp, &ctrl->routes_list, list)
|
||||
otto_l3_route_free(ctrl, r);
|
||||
rtnl_unlock();
|
||||
rhltable_destroy(&ctrl->routes);
|
||||
}
|
||||
|
||||
struct otto_l3_flush_work {
|
||||
@@ -3790,6 +3790,7 @@ int otto_l3_probe(struct device *dev, struct rtl838x_switch_priv *priv)
|
||||
err = register_netevent_notifier(&ctrl->ne_nb);
|
||||
if (err) {
|
||||
ctrl->ne_nb.notifier_call = NULL;
|
||||
otto_l3_remove(priv);
|
||||
return dev_err_probe(dev, err, "Failed to register netevent notifier\n");
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user