diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2026-06-15 15:29:34 -0700 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-06-16 14:37:06 -0700 |
| commit | 023f9b0f2f4ffbf78ce9dfb8fbacb767c8e97162 (patch) | |
| tree | d4e35425926f86ef0afd8b411f8eb62852c27534 /net | |
| parent | ffaf8967735e7271a4a1362840bcfbbf2a7a722b (diff) | |
appletalk: stop storing per-interface state in struct net_device
AppleTalk keeps its per-interface control block (struct atalk_iface)
directly in struct netdevice (dev->atalk_ptr). This is the only thing
tying the protocol into the core net_device layout and is the sole
blocker to moving AppleTalk out of tree.
Replace dev->atalk_ptr with a small ifindex-keyed hashtable internal
to ddp.c. The existing atalk_interfaces list stays the owner of the iface
objects; the hashtable is purely a fast dev->iface index and reuses
the same atalk_interfaces_lock.
AFAICT this patch does not make this code any more racy than it already
is, I'm sure Sashiko will point out some basically existing bugs.
AFAICT atalk_interfaces_lock is the innermost lock already.
Acked-by: Stephen Hemminger <stephen@networkplumber.org>
Link: https://patch.msgid.link/20260615222935.947233-2-kuba@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net')
| -rw-r--r-- | net/appletalk/ddp.c | 48 |
1 files changed, 43 insertions, 5 deletions
diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index 30a6dc06291c..afb86ce6e644 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -52,6 +52,7 @@ #include <linux/termios.h> /* For TIOCOUTQ/INQ */ #include <linux/compat.h> #include <linux/slab.h> +#include <linux/hashtable.h> #include <net/datalink.h> #include <net/psnap.h> #include <net/sock.h> @@ -204,6 +205,33 @@ DEFINE_RWLOCK(atalk_routes_lock); struct atalk_iface *atalk_interfaces; DEFINE_RWLOCK(atalk_interfaces_lock); +/* Fast dev->iface lookup, keyed on ifindex. Shares atalk_interfaces_lock with + * the atalk_interfaces list, which remains the owner of the iface objects. + */ +#define ATALK_IFACE_HASH_BITS 8 +static DEFINE_HASHTABLE(atalk_iface_hash, ATALK_IFACE_HASH_BITS); + +/* Find the iface for @dev. Caller must hold atalk_interfaces_lock. */ +static struct atalk_iface *__atalk_find_dev(struct net_device *dev) +{ + struct atalk_iface *iface; + + hash_for_each_possible(atalk_iface_hash, iface, hash_node, dev->ifindex) + if (iface->dev == dev) + return iface; + return NULL; +} + +struct atalk_iface *atalk_find_dev(struct net_device *dev) +{ + struct atalk_iface *iface; + + read_lock_bh(&atalk_interfaces_lock); + iface = __atalk_find_dev(dev); + read_unlock_bh(&atalk_interfaces_lock); + return iface; +} + /* For probing devices or in a routerless network */ struct atalk_route atrtr_default; @@ -221,9 +249,9 @@ static void atif_drop_device(struct net_device *dev) while ((tmp = *iface) != NULL) { if (tmp->dev == dev) { *iface = tmp->next; + hash_del(&tmp->hash_node); dev_put(dev); kfree(tmp); - dev->atalk_ptr = NULL; } else iface = &tmp->next; } @@ -240,13 +268,13 @@ static struct atalk_iface *atif_add_device(struct net_device *dev, dev_hold(dev); iface->dev = dev; - dev->atalk_ptr = iface; iface->address = *sa; iface->status = 0; write_lock_bh(&atalk_interfaces_lock); iface->next = atalk_interfaces; atalk_interfaces = iface; + hash_add(atalk_iface_hash, &iface->hash_node, dev->ifindex); write_unlock_bh(&atalk_interfaces_lock); out: return iface; @@ -347,8 +375,15 @@ static int atif_proxy_probe_device(struct atalk_iface *atif, struct atalk_addr *atalk_find_dev_addr(struct net_device *dev) { - struct atalk_iface *iface = dev->atalk_ptr; - return iface ? &iface->address : NULL; + struct atalk_addr *addr = NULL; + struct atalk_iface *iface; + + read_lock_bh(&atalk_interfaces_lock); + iface = __atalk_find_dev(dev); + if (iface) + addr = &iface->address; + read_unlock_bh(&atalk_interfaces_lock); + return addr; } static struct atalk_addr *atalk_find_primary(void) @@ -388,8 +423,10 @@ out: */ static struct atalk_iface *atalk_find_anynet(int node, struct net_device *dev) { - struct atalk_iface *iface = dev->atalk_ptr; + struct atalk_iface *iface; + read_lock_bh(&atalk_interfaces_lock); + iface = __atalk_find_dev(dev); if (!iface || iface->status & ATIF_PROBE) goto out_err; @@ -398,6 +435,7 @@ static struct atalk_iface *atalk_find_anynet(int node, struct net_device *dev) node != ATADDR_ANYNODE) goto out_err; out: + read_unlock_bh(&atalk_interfaces_lock); return iface; out_err: iface = NULL; |
