Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

hsr: Use a single struct for self_node.

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>

authored by

Sebastian Andrzej Siewior and committed by
Jakub Kicinski
20d3c1e9 5c7aa132

+35 -37
-1
net/hsr/hsr_device.c
··· 490 490 hsr = netdev_priv(hsr_dev); 491 491 INIT_LIST_HEAD(&hsr->ports); 492 492 INIT_LIST_HEAD(&hsr->node_db); 493 - INIT_LIST_HEAD(&hsr->self_node_db); 494 493 spin_lock_init(&hsr->list_lock); 495 494 496 495 eth_hw_addr_set(hsr_dev, slave[0]->dev_addr);
+28 -35
net/hsr/hsr_framereg.c
··· 38 38 39 39 bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr) 40 40 { 41 - struct hsr_node *node; 41 + struct hsr_self_node *sn; 42 + bool ret = false; 42 43 43 - node = list_first_or_null_rcu(&hsr->self_node_db, struct hsr_node, 44 - mac_list); 45 - if (!node) { 44 + rcu_read_lock(); 45 + sn = rcu_dereference(hsr->self_node); 46 + if (!sn) { 46 47 WARN_ONCE(1, "HSR: No self node\n"); 47 - return false; 48 + goto out; 48 49 } 49 50 50 - if (ether_addr_equal(addr, node->macaddress_A)) 51 - return true; 52 - if (ether_addr_equal(addr, node->macaddress_B)) 53 - return true; 54 - 55 - return false; 51 + if (ether_addr_equal(addr, sn->macaddress_A) || 52 + ether_addr_equal(addr, sn->macaddress_B)) 53 + ret = true; 54 + out: 55 + rcu_read_unlock(); 56 + return ret; 56 57 } 57 58 58 59 /* Search for mac entry. Caller must hold rcu read lock. ··· 71 70 return NULL; 72 71 } 73 72 74 - /* Helper for device init; the self_node_db is used in hsr_rcv() to recognize 73 + /* Helper for device init; the self_node is used in hsr_rcv() to recognize 75 74 * frames from self that's been looped over the HSR ring. 76 75 */ 77 76 int hsr_create_self_node(struct hsr_priv *hsr, 78 77 const unsigned char addr_a[ETH_ALEN], 79 78 const unsigned char addr_b[ETH_ALEN]) 80 79 { 81 - struct list_head *self_node_db = &hsr->self_node_db; 82 - struct hsr_node *node, *oldnode; 80 + struct hsr_self_node *sn, *old; 83 81 84 - node = kmalloc(sizeof(*node), GFP_KERNEL); 85 - if (!node) 82 + sn = kmalloc(sizeof(*sn), GFP_KERNEL); 83 + if (!sn) 86 84 return -ENOMEM; 87 85 88 - ether_addr_copy(node->macaddress_A, addr_a); 89 - ether_addr_copy(node->macaddress_B, addr_b); 86 + ether_addr_copy(sn->macaddress_A, addr_a); 87 + ether_addr_copy(sn->macaddress_B, addr_b); 90 88 91 89 spin_lock_bh(&hsr->list_lock); 92 - oldnode = list_first_or_null_rcu(self_node_db, 93 - struct hsr_node, mac_list); 94 - if (oldnode) { 95 - list_replace_rcu(&oldnode->mac_list, &node->mac_list); 96 - spin_unlock_bh(&hsr->list_lock); 97 - kfree_rcu(oldnode, rcu_head); 98 - } else { 99 - list_add_tail_rcu(&node->mac_list, self_node_db); 100 - spin_unlock_bh(&hsr->list_lock); 101 - } 90 + old = rcu_replace_pointer(hsr->self_node, sn, 91 + lockdep_is_held(&hsr->list_lock)); 92 + spin_unlock_bh(&hsr->list_lock); 102 93 94 + if (old) 95 + kfree_rcu(old, rcu_head); 103 96 return 0; 104 97 } 105 98 106 99 void hsr_del_self_node(struct hsr_priv *hsr) 107 100 { 108 - struct list_head *self_node_db = &hsr->self_node_db; 109 - struct hsr_node *node; 101 + struct hsr_self_node *old; 110 102 111 103 spin_lock_bh(&hsr->list_lock); 112 - node = list_first_or_null_rcu(self_node_db, struct hsr_node, mac_list); 113 - if (node) { 114 - list_del_rcu(&node->mac_list); 115 - kfree_rcu(node, rcu_head); 116 - } 104 + old = rcu_replace_pointer(hsr->self_node, NULL, 105 + lockdep_is_held(&hsr->list_lock)); 117 106 spin_unlock_bh(&hsr->list_lock); 107 + if (old) 108 + kfree_rcu(old, rcu_head); 118 109 } 119 110 120 111 void hsr_del_nodes(struct list_head *node_db)
+7 -1
net/hsr/hsr_main.h
··· 182 182 void (*update_san_info)(struct hsr_node *node, bool is_sup); 183 183 }; 184 184 185 + struct hsr_self_node { 186 + unsigned char macaddress_A[ETH_ALEN]; 187 + unsigned char macaddress_B[ETH_ALEN]; 188 + struct rcu_head rcu_head; 189 + }; 190 + 185 191 struct hsr_priv { 186 192 struct rcu_head rcu_head; 187 193 struct list_head ports; 188 194 struct list_head node_db; /* Known HSR nodes */ 189 - struct list_head self_node_db; /* MACs of slaves */ 195 + struct hsr_self_node __rcu *self_node; /* MACs of slaves */ 190 196 struct timer_list announce_timer; /* Supervision frame dispatch */ 191 197 struct timer_list prune_timer; 192 198 int announce_count;