diff options
author | Cong Wang <xiyou.wangcong@gmail.com> | 2019-07-03 20:21:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-07-05 18:22:27 -0400 |
commit | b9a1e627405d68d475a3c1f35e685ccfb5bbe668 (patch) | |
tree | 4130c796a3b6477e01126514e08f9cb2fc91f4b6 | |
parent | 619afef01f74f3572b5e9a266c1230dc83761eec (diff) |
hsr: implement dellink to clean up resources
hsr_link_ops implements ->newlink() but not ->dellink(),
which leads that resources not released after removing the device,
particularly the entries in self_node_db and node_db.
So add ->dellink() implementation to replace the priv_destructor.
This also makes the code slightly easier to understand.
Reported-by: syzbot+c6167ec3de7def23d1e8@syzkaller.appspotmail.com
Cc: Arvid Brodin <arvid.brodin@alten.se>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/hsr/hsr_device.c | 13 | ||||
-rw-r--r-- | net/hsr/hsr_device.h | 1 | ||||
-rw-r--r-- | net/hsr/hsr_framereg.c | 11 | ||||
-rw-r--r-- | net/hsr/hsr_framereg.h | 3 | ||||
-rw-r--r-- | net/hsr/hsr_netlink.c | 7 |
5 files changed, 25 insertions, 10 deletions
diff --git a/net/hsr/hsr_device.c b/net/hsr/hsr_device.c index f48b6a275cf0..4ea7d54a8262 100644 --- a/net/hsr/hsr_device.c +++ b/net/hsr/hsr_device.c | |||
@@ -344,10 +344,7 @@ static void hsr_announce(struct timer_list *t) | |||
344 | rcu_read_unlock(); | 344 | rcu_read_unlock(); |
345 | } | 345 | } |
346 | 346 | ||
347 | /* According to comments in the declaration of struct net_device, this function | 347 | void hsr_dev_destroy(struct net_device *hsr_dev) |
348 | * is "Called from unregister, can be used to call free_netdev". Ok then... | ||
349 | */ | ||
350 | static void hsr_dev_destroy(struct net_device *hsr_dev) | ||
351 | { | 348 | { |
352 | struct hsr_priv *hsr; | 349 | struct hsr_priv *hsr; |
353 | struct hsr_port *port; | 350 | struct hsr_port *port; |
@@ -357,15 +354,16 @@ static void hsr_dev_destroy(struct net_device *hsr_dev) | |||
357 | 354 | ||
358 | hsr_debugfs_term(hsr); | 355 | hsr_debugfs_term(hsr); |
359 | 356 | ||
360 | rtnl_lock(); | ||
361 | list_for_each_entry_safe(port, tmp, &hsr->ports, port_list) | 357 | list_for_each_entry_safe(port, tmp, &hsr->ports, port_list) |
362 | hsr_del_port(port); | 358 | hsr_del_port(port); |
363 | rtnl_unlock(); | ||
364 | 359 | ||
365 | del_timer_sync(&hsr->prune_timer); | 360 | del_timer_sync(&hsr->prune_timer); |
366 | del_timer_sync(&hsr->announce_timer); | 361 | del_timer_sync(&hsr->announce_timer); |
367 | 362 | ||
368 | synchronize_rcu(); | 363 | synchronize_rcu(); |
364 | |||
365 | hsr_del_self_node(&hsr->self_node_db); | ||
366 | hsr_del_nodes(&hsr->node_db); | ||
369 | } | 367 | } |
370 | 368 | ||
371 | static const struct net_device_ops hsr_device_ops = { | 369 | static const struct net_device_ops hsr_device_ops = { |
@@ -392,7 +390,6 @@ void hsr_dev_setup(struct net_device *dev) | |||
392 | dev->priv_flags |= IFF_NO_QUEUE; | 390 | dev->priv_flags |= IFF_NO_QUEUE; |
393 | 391 | ||
394 | dev->needs_free_netdev = true; | 392 | dev->needs_free_netdev = true; |
395 | dev->priv_destructor = hsr_dev_destroy; | ||
396 | 393 | ||
397 | dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | | 394 | dev->hw_features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | |
398 | NETIF_F_GSO_MASK | NETIF_F_HW_CSUM | | 395 | NETIF_F_GSO_MASK | NETIF_F_HW_CSUM | |
@@ -497,7 +494,7 @@ fail: | |||
497 | list_for_each_entry_safe(port, tmp, &hsr->ports, port_list) | 494 | list_for_each_entry_safe(port, tmp, &hsr->ports, port_list) |
498 | hsr_del_port(port); | 495 | hsr_del_port(port); |
499 | err_add_port: | 496 | err_add_port: |
500 | hsr_del_node(&hsr->self_node_db); | 497 | hsr_del_self_node(&hsr->self_node_db); |
501 | 498 | ||
502 | return res; | 499 | return res; |
503 | } | 500 | } |
diff --git a/net/hsr/hsr_device.h b/net/hsr/hsr_device.h index 6d7759c4f5f9..d0fa6b0696d2 100644 --- a/net/hsr/hsr_device.h +++ b/net/hsr/hsr_device.h | |||
@@ -14,6 +14,7 @@ | |||
14 | void hsr_dev_setup(struct net_device *dev); | 14 | void hsr_dev_setup(struct net_device *dev); |
15 | int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], | 15 | int hsr_dev_finalize(struct net_device *hsr_dev, struct net_device *slave[2], |
16 | unsigned char multicast_spec, u8 protocol_version); | 16 | unsigned char multicast_spec, u8 protocol_version); |
17 | void hsr_dev_destroy(struct net_device *hsr_dev); | ||
17 | void hsr_check_carrier_and_operstate(struct hsr_priv *hsr); | 18 | void hsr_check_carrier_and_operstate(struct hsr_priv *hsr); |
18 | bool is_hsr_master(struct net_device *dev); | 19 | bool is_hsr_master(struct net_device *dev); |
19 | int hsr_get_max_mtu(struct hsr_priv *hsr); | 20 | int hsr_get_max_mtu(struct hsr_priv *hsr); |
diff --git a/net/hsr/hsr_framereg.c b/net/hsr/hsr_framereg.c index 2d7a19750436..292be446007b 100644 --- a/net/hsr/hsr_framereg.c +++ b/net/hsr/hsr_framereg.c | |||
@@ -104,7 +104,7 @@ int hsr_create_self_node(struct list_head *self_node_db, | |||
104 | return 0; | 104 | return 0; |
105 | } | 105 | } |
106 | 106 | ||
107 | void hsr_del_node(struct list_head *self_node_db) | 107 | void hsr_del_self_node(struct list_head *self_node_db) |
108 | { | 108 | { |
109 | struct hsr_node *node; | 109 | struct hsr_node *node; |
110 | 110 | ||
@@ -117,6 +117,15 @@ void hsr_del_node(struct list_head *self_node_db) | |||
117 | } | 117 | } |
118 | } | 118 | } |
119 | 119 | ||
120 | void hsr_del_nodes(struct list_head *node_db) | ||
121 | { | ||
122 | struct hsr_node *node; | ||
123 | struct hsr_node *tmp; | ||
124 | |||
125 | list_for_each_entry_safe(node, tmp, node_db, mac_list) | ||
126 | kfree(node); | ||
127 | } | ||
128 | |||
120 | /* Allocate an hsr_node and add it to node_db. 'addr' is the node's address_A; | 129 | /* Allocate an hsr_node and add it to node_db. 'addr' is the node's address_A; |
121 | * seq_out is used to initialize filtering of outgoing duplicate frames | 130 | * seq_out is used to initialize filtering of outgoing duplicate frames |
122 | * originating from the newly added node. | 131 | * originating from the newly added node. |
diff --git a/net/hsr/hsr_framereg.h b/net/hsr/hsr_framereg.h index a3bdcdab469d..89a3ce38151d 100644 --- a/net/hsr/hsr_framereg.h +++ b/net/hsr/hsr_framereg.h | |||
@@ -12,7 +12,8 @@ | |||
12 | 12 | ||
13 | struct hsr_node; | 13 | struct hsr_node; |
14 | 14 | ||
15 | void hsr_del_node(struct list_head *self_node_db); | 15 | void hsr_del_self_node(struct list_head *self_node_db); |
16 | void hsr_del_nodes(struct list_head *node_db); | ||
16 | struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[], | 17 | struct hsr_node *hsr_add_node(struct list_head *node_db, unsigned char addr[], |
17 | u16 seq_out); | 18 | u16 seq_out); |
18 | struct hsr_node *hsr_get_node(struct hsr_port *port, struct sk_buff *skb, | 19 | struct hsr_node *hsr_get_node(struct hsr_port *port, struct sk_buff *skb, |
diff --git a/net/hsr/hsr_netlink.c b/net/hsr/hsr_netlink.c index 8f8337f893ba..160edd24de4e 100644 --- a/net/hsr/hsr_netlink.c +++ b/net/hsr/hsr_netlink.c | |||
@@ -69,6 +69,12 @@ static int hsr_newlink(struct net *src_net, struct net_device *dev, | |||
69 | return hsr_dev_finalize(dev, link, multicast_spec, hsr_version); | 69 | return hsr_dev_finalize(dev, link, multicast_spec, hsr_version); |
70 | } | 70 | } |
71 | 71 | ||
72 | static void hsr_dellink(struct net_device *hsr_dev, struct list_head *head) | ||
73 | { | ||
74 | hsr_dev_destroy(hsr_dev); | ||
75 | unregister_netdevice_queue(hsr_dev, head); | ||
76 | } | ||
77 | |||
72 | static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) | 78 | static int hsr_fill_info(struct sk_buff *skb, const struct net_device *dev) |
73 | { | 79 | { |
74 | struct hsr_priv *hsr; | 80 | struct hsr_priv *hsr; |
@@ -113,6 +119,7 @@ static struct rtnl_link_ops hsr_link_ops __read_mostly = { | |||
113 | .priv_size = sizeof(struct hsr_priv), | 119 | .priv_size = sizeof(struct hsr_priv), |
114 | .setup = hsr_dev_setup, | 120 | .setup = hsr_dev_setup, |
115 | .newlink = hsr_newlink, | 121 | .newlink = hsr_newlink, |
122 | .dellink = hsr_dellink, | ||
116 | .fill_info = hsr_fill_info, | 123 | .fill_info = hsr_fill_info, |
117 | }; | 124 | }; |
118 | 125 | ||