Thread (17 messages) 17 messages, 6 authors, 12d ago

[PATCH v3 net-next 1/6] net: Order blackhole_netdev_init(), inet_init(), and inet6_init().

flat view
COOLING12d IN NET-NEXT

From: Kuniyuki Iwashima <kuniyu@google.com>
Date: 2026-10-01 20:47:57
Subsystem: networking drivers, networking [general], the rest · Maintainers: Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

Revision v3 of 2 in this series; queued in net-next as 20dff14006b1 on 2026-10-06.

Revisions (2)
  1. v2 [diff vs current]
  2. v3 current
Commit 309b905deee5 ("ipv6: convert CONFIG_IPV6 to built-in
only and clean up Kconfigs") started to call inet6_init() as
device_initcall().

It explains the reason as a race condition on IPv6 addrconf,
but this is not accurate.

The change initially used fs_initcall() but switched to
device_initcall() due to the null-ptr-deref stack trace in
the link below.

It happened because blackhole_netdev_init() uses device_initcall()
and blackhole_netdev was NULL when addrconf_init() called
ipv6_add_dev(blackhole_netdev).

Due to the order in Kbuild,

  $ cat -n Kbuild | grep -E "(drivers|net)"
     111	obj-y			+= drivers/
     114	obj-$(CONFIG_NET)	+= net/

using device_initcall() for IPv6 allows built-in drivers to
be initialised earlier, which requires unnecessary NULL checks.

For the same ordering reason, IPv4 uses late_initcall() to
initialise blackhole_netdev.

Given loopback_net_ops is registered in net_dev_init() at
subsys_initcall(), blackhole_netdev_init() can be called
after that.

In addition, some places assume that IPv4 must be initialised
before IPv6.  For example, mptcp_proto_v6_init() copies
mptcp_prot to mptcp_v6_prot, which would otherwise have NULL
mptcp_v6_prot.h.hashinfo.

Let's explicitly order blackhole_netdev_init() -> inet_init()
-> inet6_init() before device_initcall() with 3 different
initcall levels:

  subsys_initcall      : 4  : net_dev_init()
  subsys_initcall_sync : 4s : blackhole_netdev_init()
  fs_initcall          : 5  : inet_init()
  fs_initcall_sync     : 5s : inet6_init()
  device_initcall      : 6  : built-in drivers

Note that both IPv4 and IPv6 can still use fs_initcall() thanks
to the order in net/Makefile, but explicit ordering would be
less error-prone.

  $ cat -n net/Makefile | grep ipv
      17	obj-$(CONFIG_INET)		+= ipv4/
      22	obj-y				+= ipv6/

Link: https://lore.kernel.org/netdev/20260309074758.0ea95a18@kernel.org/ (local)
Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
---
Cc: Fernando Fernandez Mancera <redacted>
---
 drivers/net/loopback.c | 2 +-
 net/ipv6/af_inet6.c    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c
index 1fb6ce6843ad..55ecd5ebac0f 100644
--- a/drivers/net/loopback.c
+++ b/drivers/net/loopback.c
@@ -289,4 +289,4 @@ static int __init blackhole_netdev_init(void)
 	return 0;
 }
 
-device_initcall(blackhole_netdev_init);
+subsys_initcall_sync(blackhole_netdev_init);
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index f0efdc13baf4..a9b8b4b42a1a 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -1217,4 +1217,4 @@ static int __init inet6_init(void)
 	proto_unregister(&tcpv6_prot);
 	goto out;
 }
-device_initcall(inet6_init);
+fs_initcall_sync(inet6_init);
-- 
2.56.0.rc1.315.gc6ed9934b7-goog
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help