[PATCH v2] batman-adv: handle errors in batadv_init()
From: Minhong He
Date: Wed Jul 29 2026 - 04:47:26 EST
batadv_init() ignores errors from several initialization helpers, so the
module can load without those registrations in place.
Check the fallible init steps and unwind prior initialization in reverse
order of acquisition on failure.
Signed-off-by: Minhong He <heminhong@xxxxxxxxxx>
---
v2:
- Drop the "net" subject prefix; this targets the batman-adv tree
- Also check batadv_v_init()/batadv_iv_init()/batadv_netlink_register()
- Add batadv_v_deinit()/batadv_iv_deinit() helpers for unwind
- Call rcu_barrier() before batadv_wifi_net_devices_deinit()
- Shorten the subject
v1: https://lore.kernel.org/all/20260728031050.76643-1-heminhong@xxxxxxxxxx/
net/batman-adv/bat_iv_ogm.c | 8 +++++++
net/batman-adv/bat_iv_ogm.h | 1 +
net/batman-adv/bat_v.c | 9 ++++++++
net/batman-adv/bat_v.h | 5 ++++
net/batman-adv/main.c | 46 +++++++++++++++++++++++++++++--------
net/batman-adv/netlink.c | 6 ++++-
net/batman-adv/netlink.h | 2 +-
7 files changed, 66 insertions(+), 11 deletions(-)
diff --git a/net/batman-adv/bat_iv_ogm.c b/net/batman-adv/bat_iv_ogm.c
index 22622283f59b..625d4d2ac262 100644
--- a/net/batman-adv/bat_iv_ogm.c
+++ b/net/batman-adv/bat_iv_ogm.c
@@ -2633,3 +2633,11 @@ int __init batadv_iv_init(void)
out:
return ret;
}
+
+/**
+ * batadv_iv_deinit() - B.A.T.M.A.N. IV deinitialization function
+ */
+void batadv_iv_deinit(void)
+{
+ batadv_recv_handler_unregister(BATADV_IV_OGM);
+}
diff --git a/net/batman-adv/bat_iv_ogm.h b/net/batman-adv/bat_iv_ogm.h
index 04b01bd684e8..90318801aeaf 100644
--- a/net/batman-adv/bat_iv_ogm.h
+++ b/net/batman-adv/bat_iv_ogm.h
@@ -10,5 +10,6 @@
#include "main.h"
int batadv_iv_init(void);
+void batadv_iv_deinit(void);
#endif /* _NET_BATMAN_ADV_BAT_IV_OGM_H_ */
diff --git a/net/batman-adv/bat_v.c b/net/batman-adv/bat_v.c
index db6f5bdcaa98..c1f2d37aa724 100644
--- a/net/batman-adv/bat_v.c
+++ b/net/batman-adv/bat_v.c
@@ -888,3 +888,12 @@ int __init batadv_v_init(void)
return ret;
}
+
+/**
+ * batadv_v_deinit() - B.A.T.M.A.N. V deinitialization function
+ */
+void batadv_v_deinit(void)
+{
+ batadv_recv_handler_unregister(BATADV_OGM2);
+ batadv_recv_handler_unregister(BATADV_ELP);
+}
diff --git a/net/batman-adv/bat_v.h b/net/batman-adv/bat_v.h
index 964431f4dc8d..76bd969e79a2 100644
--- a/net/batman-adv/bat_v.h
+++ b/net/batman-adv/bat_v.h
@@ -12,6 +12,7 @@
#ifdef CONFIG_BATMAN_ADV_BATMAN_V
int batadv_v_init(void);
+void batadv_v_deinit(void);
void batadv_v_hardif_init(struct batadv_hard_iface *hardif);
int batadv_v_mesh_init(struct batadv_priv *bat_priv);
void batadv_v_mesh_free(struct batadv_priv *bat_priv);
@@ -23,6 +24,10 @@ static inline int batadv_v_init(void)
return 0;
}
+static inline void batadv_v_deinit(void)
+{
+}
+
static inline void batadv_v_hardif_init(struct batadv_hard_iface *hardif)
{
}
diff --git a/net/batman-adv/main.c b/net/batman-adv/main.c
index 73becb054948..8fe8a2b27a74 100644
--- a/net/batman-adv/main.c
+++ b/net/batman-adv/main.c
@@ -94,35 +94,63 @@ static int __init batadv_init(void)
batadv_recv_handler_init();
- batadv_v_init();
- batadv_iv_init();
+ ret = batadv_v_init();
+ if (ret < 0)
+ goto err_tt;
+
+ ret = batadv_iv_init();
+ if (ret < 0)
+ goto err_v;
+
batadv_tp_meter_init();
batadv_event_workqueue = create_singlethread_workqueue("bat_events");
if (!batadv_event_workqueue) {
ret = -ENOMEM;
- goto err_create_wq;
+ goto err_iv;
}
ret = batadv_wifi_net_devices_init();
if (ret < 0)
- goto err_init_wifi;
+ goto err_wq;
- register_netdevice_notifier(&batadv_hard_if_notifier);
- rtnl_link_register(&batadv_link_ops);
- batadv_netlink_register();
+ ret = register_netdevice_notifier(&batadv_hard_if_notifier);
+ if (ret < 0)
+ goto err_wifi;
+
+ ret = rtnl_link_register(&batadv_link_ops);
+ if (ret < 0)
+ goto err_notifier;
+
+ ret = batadv_netlink_register();
+ if (ret < 0)
+ goto err_rtnl;
pr_info("B.A.T.M.A.N. advanced %s (compatibility version %i) loaded\n",
init_utsname()->release, BATADV_COMPAT_VERSION);
return 0;
-err_init_wifi:
+err_rtnl:
+ rtnl_link_unregister(&batadv_link_ops);
+err_notifier:
+ unregister_netdevice_notifier(&batadv_hard_if_notifier);
+err_wifi:
destroy_workqueue(batadv_event_workqueue);
batadv_event_workqueue = NULL;
rcu_barrier();
+ batadv_wifi_net_devices_deinit();
+ goto err_iv;
-err_create_wq:
+err_wq:
+ destroy_workqueue(batadv_event_workqueue);
+ batadv_event_workqueue = NULL;
+ rcu_barrier();
+err_iv:
+ batadv_iv_deinit();
+err_v:
+ batadv_v_deinit();
+err_tt:
batadv_tt_cache_destroy();
return ret;
diff --git a/net/batman-adv/netlink.c b/net/batman-adv/netlink.c
index d2bc48c70714..99341f39df2a 100644
--- a/net/batman-adv/netlink.c
+++ b/net/batman-adv/netlink.c
@@ -1550,14 +1550,18 @@ struct genl_family batadv_netlink_family __ro_after_init = {
/**
* batadv_netlink_register() - register batadv genl netlink family
+ *
+ * Return: 0 on success or negative error number in case of failure
*/
-void __init batadv_netlink_register(void)
+int __init batadv_netlink_register(void)
{
int ret;
ret = genl_register_family(&batadv_netlink_family);
if (ret)
pr_warn("unable to register netlink family\n");
+
+ return ret;
}
/**
diff --git a/net/batman-adv/netlink.h b/net/batman-adv/netlink.h
index 4eae9e5ff135..f92d3ea7d06c 100644
--- a/net/batman-adv/netlink.h
+++ b/net/batman-adv/netlink.h
@@ -12,7 +12,7 @@
#include <linux/netlink.h>
#include <linux/types.h>
-void batadv_netlink_register(void);
+int batadv_netlink_register(void);
void batadv_netlink_unregister(void);
struct net_device *batadv_netlink_get_meshif(struct netlink_callback *cb);
struct batadv_hard_iface *
--
2.25.1