diff mbox series

[v2,net,7/7] hsr: Use a single struct for self_node.

Message ID 20221121174605.2456845-8-bigeasy@linutronix.de (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series [v2,net,1/7] Revert "net: hsr: use hlist_head instead of list_head for mac addresses" | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net
netdev/fixes_present success Fixes tag present in non-next series
netdev/subject_prefix success Link
netdev/cover_letter warning Series does not have a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 0 this patch: 5
netdev/cc_maintainers warning 1 maintainers not CCed: claudiajkang@gmail.com
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 0 this patch: 5
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 124 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Sebastian Andrzej Siewior Nov. 21, 2022, 5:46 p.m. UTC
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 structured like an RCU protected pointer so
it can be replaced on the fly withou blocking the reader.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 net/hsr/hsr_device.c   |  1 -
 net/hsr/hsr_framereg.c | 63 +++++++++++++++++++-----------------------
 net/hsr/hsr_main.h     |  8 +++++-
 3 files changed, 35 insertions(+), 37 deletions(-)

Comments

Kurt Kanzenbach Nov. 22, 2022, 9:20 a.m. UTC | #1
On Mon Nov 21 2022, Sebastian Andrzej Siewior wrote:
> 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 structured like an RCU protected pointer so
                             ^ structure

> it can be replaced on the fly withou blocking the reader.
                               ^ without

>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>

Lacks a Fixes tag. Looks rather like an optimization than a bugfix? So,
maybe this one should go to net-next instead.

[snip]

> +struct hsr_self_node {
> +	unsigned char	macaddress_A[6];
                                    ^ ETH_ALEN

> +	unsigned char	macaddress_B[6];
                                    ^ ETH_ALEN
> +	struct rcu_head	rcu_head;
> +};
> +

Thanks,
Kurt
Sebastian Andrzej Siewior Nov. 22, 2022, 9:56 a.m. UTC | #2
On 2022-11-22 10:20:49 [+0100], Kurt Kanzenbach wrote:
> On Mon Nov 21 2022, Sebastian Andrzej Siewior wrote:
> > 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 structured like an RCU protected pointer so
>                              ^ structure
> 
> > it can be replaced on the fly withou blocking the reader.
>                                ^ without

argh.

> >
> > Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> 
> Lacks a Fixes tag. Looks rather like an optimization than a bugfix? So,
> maybe this one should go to net-next instead.

The initial motivation for
	hsr: Avoid double remove of a node

was to use hlist_del_init_rcu() for the remove and then use
hlist_unhashed() for the check. This got me to this because I was not
sure why we have this list for a single node which isn't needed and
looks like waste of memory and confusion (a list for a single entry?).
In the end I decided midway to stay with the list_head and just add a
`removed' field to deal with this.

Can we ignore this patch and then I repost just that one for next?

> [snip]
> 
> > +struct hsr_self_node {
> > +	unsigned char	macaddress_A[6];
>                                     ^ ETH_ALEN
> 
> > +	unsigned char	macaddress_B[6];
>                                     ^ ETH_ALEN
> > +	struct rcu_head	rcu_head;
> > +};
> > +

Sure.

> Thanks,
> Kurt
Sebastian
kernel test robot Nov. 25, 2022, 12:46 a.m. UTC | #3
Hi Sebastian,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on net/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Sebastian-Andrzej-Siewior/Revert-net-hsr-use-hlist_head-instead-of-list_head-for-mac-addresses/20221122-024634
patch link:    https://lore.kernel.org/r/20221121174605.2456845-8-bigeasy%40linutronix.de
patch subject: [PATCH v2 net 7/7] hsr: Use a single struct for self_node.
config: ia64-randconfig-s033-20221124
compiler: ia64-linux-gcc (GCC) 12.1.0
reproduce:
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # apt-get install sparse
        # sparse version: v0.6.4-39-gce1a6720-dirty
        # https://github.com/intel-lab-lkp/linux/commit/80e94f7b5ffe417abb25777833f59121dae6b17f
        git remote add linux-review https://github.com/intel-lab-lkp/linux
        git fetch --no-tags linux-review Sebastian-Andrzej-Siewior/Revert-net-hsr-use-hlist_head-instead-of-list_head-for-mac-addresses/20221122-024634
        git checkout 80e94f7b5ffe417abb25777833f59121dae6b17f
        # save the config file
        mkdir build_dir && cp config build_dir/.config
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-12.1.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=ia64 SHELL=/bin/bash drivers/hid/ net/hsr/

If you fix the issue, kindly add following tag where applicable
| Reported-by: kernel test robot <lkp@intel.com>

sparse warnings: (new ones prefixed by >>)
>> net/hsr/hsr_framereg.c:45:14: sparse: sparse: incompatible types in comparison expression (different address spaces):
>> net/hsr/hsr_framereg.c:45:14: sparse:    struct hsr_self_node [noderef] __rcu *
>> net/hsr/hsr_framereg.c:45:14: sparse:    struct hsr_self_node *
   net/hsr/hsr_framereg.c:91:15: sparse: sparse: incompatible types in comparison expression (different address spaces):
   net/hsr/hsr_framereg.c:91:15: sparse:    struct hsr_self_node [noderef] __rcu *
   net/hsr/hsr_framereg.c:91:15: sparse:    struct hsr_self_node *
   net/hsr/hsr_framereg.c:91:15: sparse: sparse: incompatible types in comparison expression (different address spaces):
   net/hsr/hsr_framereg.c:91:15: sparse:    struct hsr_self_node [noderef] __rcu *
   net/hsr/hsr_framereg.c:91:15: sparse:    struct hsr_self_node *
   net/hsr/hsr_framereg.c:105:15: sparse: sparse: incompatible types in comparison expression (different address spaces):
   net/hsr/hsr_framereg.c:105:15: sparse:    struct hsr_self_node [noderef] __rcu *
   net/hsr/hsr_framereg.c:105:15: sparse:    struct hsr_self_node *
   net/hsr/hsr_framereg.c:105:15: sparse: sparse: incompatible types in comparison expression (different address spaces):
   net/hsr/hsr_framereg.c:105:15: sparse:    struct hsr_self_node [noderef] __rcu *
   net/hsr/hsr_framereg.c:105:15: sparse:    struct hsr_self_node *

vim +45 net/hsr/hsr_framereg.c

    38	
    39	bool hsr_addr_is_self(struct hsr_priv *hsr, unsigned char *addr)
    40	{
    41		struct hsr_self_node *sn;
    42		bool ret = false;
    43	
    44		rcu_read_lock();
  > 45		sn = rcu_dereference(hsr->self_node);
    46		if (!sn) {
    47			WARN_ONCE(1, "HSR: No self node\n");
    48			goto out;
    49		}
    50	
    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;
    57	}
    58
diff mbox series

Patch

diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c
index b1e86a7265b32..5a236aae2366f 100644
--- a/net/hsr/hsr_device.c
+++ b/net/hsr/hsr_device.c
@@ -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);
diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c
index 39a6088080e93..00db74d96583d 100644
--- a/net/hsr/hsr_framereg.c
+++ b/net/hsr/hsr_framereg.c
@@ -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)
diff --git a/net/hsr/hsr_main.h b/net/hsr/hsr_main.h
index 16ae9fb09ccd2..bbbff6b71e92f 100644
--- a/net/hsr/hsr_main.h
+++ b/net/hsr/hsr_main.h
@@ -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[6];
+	unsigned char	macaddress_B[6];
+	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	*self_node;	/* MACs of slaves */
 	struct timer_list	announce_timer;	/* Supervision frame dispatch */
 	struct timer_list	prune_timer;
 	int announce_count;