OSDN Git Service

hsr: Use a single struct for self_node.
authorSebastian Andrzej Siewior <bigeasy@linutronix.de>
Tue, 29 Nov 2022 16:48:14 +0000 (17:48 +0100)
committerJakub Kicinski <kuba@kernel.org>
Fri, 2 Dec 2022 04:26:22 +0000 (20:26 -0800)
self_node_db is a list_head with one entry of struct hsr_node. The
purpose is to hold the two MAC addresses of the node itself.
It is convenient to recycle the structure. However having a list_head
and fetching always the first entry is not really optimal.

Created a new data strucure contaning the two MAC addresses named
hsr_self_node. Access that structure like an RCU protected pointer so
it can be replaced on the fly without blocking the reader.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: Kurt Kanzenbach <kurt@linutronix.de>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/hsr/hsr_device.c
net/hsr/hsr_framereg.c
net/hsr/hsr_main.h

index b1e86a7..5a236aa 100644 (file)
@@ -490,7 +490,6 @@ int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2],
        hsr = netdev_priv(hsr_dev);
        INIT_LIST_HEAD(&hsr->ports);
        INIT_LIST_HEAD(&hsr->node_db);
-       INIT_LIST_HEAD(&hsr->self_node_db);
        spin_lock_init(&hsr->list_lock);
 
        eth_hw_addr_set(hsr_dev, slave[0]->dev_addr);
index 39a6088..00db74d 100644 (file)
@@ -38,21 +38,22 @@ static bool seq_nr_after(u16 a, u16 b)
 
 bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr)
 {
-       struct hsr_node *node;
+       struct hsr_self_node *sn;
+       bool ret = false;
 
-       node = list_first_or_null_rcu(&hsr->self_node_db, struct hsr_node,
-                                     mac_list);
-       if (!node) {
+       rcu_read_lock();
+       sn = rcu_dereference(hsr->self_node);
+       if (!sn) {
                WARN_ONCE(1, "HSR: No self node\n");
-               return false;
+               goto out;
        }
 
-       if (ether_addr_equal(addr, node->macaddress_A))
-               return true;
-       if (ether_addr_equal(addr, node->macaddress_B))
-               return true;
-
-       return false;
+       if (ether_addr_equal(addr, sn->macaddress_A) ||
+           ether_addr_equal(addr, sn->macaddress_B))
+               ret = true;
+out:
+       rcu_read_unlock();
+       return ret;
 }
 
 /* Search for mac entry. Caller must hold rcu read lock.
@@ -70,50 +71,42 @@ static struct hsr_node *find_node_by_addr_A(struct list_head *node_db,
        return NULL;
 }
 
-/* Helper for device init; the self_node_db is used in hsr_rcv() to recognize
+/* Helper for device init; the self_node is used in hsr_rcv() to recognize
  * frames from self that's been looped over the HSR ring.
  */
 int hsr_create_self_node(struct hsr_priv *hsr,
                         const unsigned char addr_a[ETH_ALEN],
                         const unsigned char addr_b[ETH_ALEN])
 {
-       struct list_head *self_node_db = &hsr->self_node_db;
-       struct hsr_node *node, *oldnode;
+       struct hsr_self_node *sn, *old;
 
-       node = kmalloc(sizeof(*node), GFP_KERNEL);
-       if (!node)
+       sn = kmalloc(sizeof(*sn), GFP_KERNEL);
+       if (!sn)
                return -ENOMEM;
 
-       ether_addr_copy(node->macaddress_A, addr_a);
-       ether_addr_copy(node->macaddress_B, addr_b);
+       ether_addr_copy(sn->macaddress_A, addr_a);
+       ether_addr_copy(sn->macaddress_B, addr_b);
 
        spin_lock_bh(&hsr->list_lock);
-       oldnode = list_first_or_null_rcu(self_node_db,
-                                        struct hsr_node, mac_list);
-       if (oldnode) {
-               list_replace_rcu(&oldnode->mac_list, &node->mac_list);
-               spin_unlock_bh(&hsr->list_lock);
-               kfree_rcu(oldnode, rcu_head);
-       } else {
-               list_add_tail_rcu(&node->mac_list, self_node_db);
-               spin_unlock_bh(&hsr->list_lock);
-       }
+       old = rcu_replace_pointer(hsr->self_node, sn,
+                                 lockdep_is_held(&hsr->list_lock));
+       spin_unlock_bh(&hsr->list_lock);
 
+       if (old)
+               kfree_rcu(old, rcu_head);
        return 0;
 }
 
 void hsr_del_self_node(struct hsr_priv *hsr)
 {
-       struct list_head *self_node_db = &hsr->self_node_db;
-       struct hsr_node *node;
+       struct hsr_self_node *old;
 
        spin_lock_bh(&hsr->list_lock);
-       node = list_first_or_null_rcu(self_node_db, struct hsr_node, mac_list);
-       if (node) {
-               list_del_rcu(&node->mac_list);
-               kfree_rcu(node, rcu_head);
-       }
+       old = rcu_replace_pointer(hsr->self_node, NULL,
+                                 lockdep_is_held(&hsr->list_lock));
        spin_unlock_bh(&hsr->list_lock);
+       if (old)
+               kfree_rcu(old, rcu_head);
 }
 
 void hsr_del_nodes(struct list_head *node_db)
index 16ae9fb..5584c80 100644 (file)
@@ -182,11 +182,17 @@ struct hsr_proto_ops {
        void (*update_san_info)(struct hsr_node *node, bool is_sup);
 };
 
+struct hsr_self_node {
+       unsigned char   macaddress_A[ETH_ALEN];
+       unsigned char   macaddress_B[ETH_ALEN];
+       struct rcu_head rcu_head;
+};
+
 struct hsr_priv {
        struct rcu_head         rcu_head;
        struct list_head        ports;
        struct list_head        node_db;        /* Known HSR nodes */
-       struct list_head        self_node_db;   /* MACs of slaves */
+       struct hsr_self_node    __rcu *self_node;       /* MACs of slaves */
        struct timer_list       announce_timer; /* Supervision frame dispatch */
        struct timer_list       prune_timer;
        int announce_count;