mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
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>
This commit is contained in:
@@ -90,7 +90,6 @@ struct inet6_dev* ip6_ptr read_mostly
|
||||
struct vlan_info* vlan_info
|
||||
struct dsa_port* dsa_ptr
|
||||
struct tipc_bearer* tipc_ptr
|
||||
void* atalk_ptr
|
||||
struct wireless_dev* ieee80211_ptr
|
||||
struct wpan_dev* ieee802154_ptr
|
||||
struct mpls_dev* mpls_ptr
|
||||
|
||||
@@ -30,6 +30,7 @@ struct atalk_iface {
|
||||
#define ATIF_PROBE_FAIL 2 /* Probe collided */
|
||||
struct atalk_netrange nets;
|
||||
struct atalk_iface *next;
|
||||
struct hlist_node hash_node; /* keyed on dev->ifindex */
|
||||
};
|
||||
|
||||
struct atalk_sock {
|
||||
@@ -113,12 +114,7 @@ extern int aarp_proto_init(void);
|
||||
/* Inter module exports */
|
||||
|
||||
/* Give a device find its atif control structure */
|
||||
#if IS_ENABLED(CONFIG_ATALK)
|
||||
static inline struct atalk_iface *atalk_find_dev(struct net_device *dev)
|
||||
{
|
||||
return dev->atalk_ptr;
|
||||
}
|
||||
#endif
|
||||
extern struct atalk_iface *atalk_find_dev(struct net_device *dev);
|
||||
|
||||
extern struct atalk_addr *atalk_find_dev_addr(struct net_device *dev);
|
||||
extern struct net_device *atrtr_get_dev(struct atalk_addr *sa);
|
||||
|
||||
@@ -1947,7 +1947,6 @@ enum netdev_reg_state {
|
||||
* @vlan_info: VLAN info
|
||||
* @dsa_ptr: dsa specific data
|
||||
* @tipc_ptr: TIPC specific data
|
||||
* @atalk_ptr: AppleTalk link
|
||||
* @ip_ptr: IPv4 specific data
|
||||
* @ip6_ptr: IPv6 specific data
|
||||
* @ieee80211_ptr: IEEE 802.11 specific data, assign before registering
|
||||
@@ -2349,9 +2348,6 @@ struct net_device {
|
||||
#if IS_ENABLED(CONFIG_TIPC)
|
||||
struct tipc_bearer __rcu *tipc_ptr;
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_ATALK)
|
||||
void *atalk_ptr;
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_CFG80211)
|
||||
struct wireless_dev *ieee80211_ptr;
|
||||
#endif
|
||||
|
||||
@@ -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 @@ static struct atalk_addr *atalk_find_primary(void)
|
||||
*/
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user