@@ -412,9 +412,9 @@ void wireless_send_event(struct net_device *dev, unsigned int cmd,
union iwreq_data *wrqu, const char *extra);
#ifdef CONFIG_WEXT_CORE
/* flush all previous wext events - if work is done from netdev notifiers */
-void wireless_nlevent_flush(void);
+void wireless_nlevent_flush(struct net *net);
#else
-static inline void wireless_nlevent_flush(void) {}
+static inline void wireless_nlevent_flush(struct net *net) {}
#endif
/* We may need a function to send a stream of events to user space.
@@ -1629,7 +1629,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb,
return NOTIFY_DONE;
}
- wireless_nlevent_flush();
+ wireless_nlevent_flush(dev_net(dev));
return NOTIFY_OK;
}
@@ -345,6 +345,7 @@ static const int compat_event_type_size[] = {
/* IW event code */
struct wext_net {
+ struct net *net;
struct sk_buff_head nlevents;
struct work_struct nlevent_work;
};
@@ -356,26 +357,22 @@ static struct wext_net *wext_net(struct net *net)
return net_generic(net, wext_net_id);
}
-void wireless_nlevent_flush(void)
+void wireless_nlevent_flush(struct net *net)
{
+ struct wext_net *wnet = wext_net(net);
struct sk_buff *skb;
- struct net *net;
- down_read(&net_rwsem);
- for_each_net(net) {
- struct wext_net *wnet = wext_net(net);
- while ((skb = skb_dequeue(&wnet->nlevents)))
- rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL,
- GFP_KERNEL);
- }
- up_read(&net_rwsem);
+ while ((skb = skb_dequeue(&wnet->nlevents)))
+ rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
}
EXPORT_SYMBOL_GPL(wireless_nlevent_flush);
static int wext_netdev_notifier_call(struct notifier_block *nb,
unsigned long state, void *ptr)
{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+
/*
* When a netdev changes state in any way, flush all pending messages
* to avoid them going out in a strange order, e.g. RTM_NEWLINK after
@@ -383,7 +380,7 @@ static int wext_netdev_notifier_call(struct notifier_block *nb,
* or similar - all of which could otherwise happen due to delays from
* schedule_work().
*/
- wireless_nlevent_flush();
+ wireless_nlevent_flush(dev_net(dev));
return NOTIFY_OK;
}
@@ -395,13 +392,17 @@ static struct notifier_block wext_netdev_notifier = {
/* Process events generated by the wireless layer or the driver. */
static void wireless_nlevent_process(struct work_struct *work)
{
- wireless_nlevent_flush();
+ struct wext_net *wnet;
+
+ wnet = container_of(work, struct wext_net, nlevent_work);
+ wireless_nlevent_flush(wnet->net);
}
static int __net_init wext_pernet_init(struct net *net)
{
struct wext_net *wnet = wext_net(net);
+ wnet->net = net;
skb_queue_head_init(&wnet->nlevents);
INIT_WORK(&wnet->nlevent_work, wireless_nlevent_process);
Commit 8bf862739a77 ("wext: fix message delay/ordering") introduced wext_netdev_notifier_call() to avoid message delay and out-of-order. The notifier calls wireless_nlevent_flush(), which iterates all netns. The problem is that this happens for any event and netdev, even if the host does not have a wext device. This is too noisy, especially on a host with thousands of netns as reported by Alexandre Ferrieux. Given that the wext event queue was implemented in struct net, wireless_nlevent_flush() does not need to iterate all netns. Let's avoid unnecessary netns iteration in wireless_nlevent_flush(). Reported-by: Alexandre Ferrieux <alexandre.ferrieux@gmail.com> Closes: https://lore.kernel.org/netdev/CAKYWH0Ti3=4GeeuVyWKJ9LyTuRnf3Wy9GKg4Jb7tdeaT39qADA@mail.gmail.com/ Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com> --- include/net/iw_handler.h | 4 ++-- net/wireless/core.c | 2 +- net/wireless/wext-core.c | 25 +++++++++++++------------ 3 files changed, 16 insertions(+), 15 deletions(-)