From: Johannes Berg <johannes@sipsolutions.net>
To: David Miller <davem@davemloft.net>, netdev@vger.kernel.org
Subject: Re: [PATCH] net: Fix inconsistent teardown and release of private netdev state.
Date: Fri, 09 Jun 2017 14:45:25 +0200 [thread overview]
Message-ID: <1497012325.2424.12.camel@sipsolutions.net> (raw)
In-Reply-To: <20170607.155411.201795978436906426.davem@davemloft.net> (sfid-20170607_215419_417472_E8ADEEB0)
Hi Dave,
I hope you don't mind a question or two for my understanding here.
Actually, this got pretty long... but I think there's a bug in here.
(For background, I'm looking into this because I'm interested in what
to do about backporting this to older kernels, or better, how to deal
with it in the backports project that tries to use the normal code as
is, backporting helper functions etc., which won't be possible here)
Under drivers/ in general, I count more than 400 calls to
register_netdev[ice](), but only 39 that set the new needs_free_netdev.
Some will overlap and have the same ops, but still, that's a rather
small portion of them. The logic means those that don't set
needs_free_netdev can't really use the new priv_destructor (previously
destructor), I think? It seems to me that priv_destructor should imply
needs_free_netdev (though not necessarily the other way around).
I guess this must mean that that all others are dealing with the
problem "manually", right? Perhaps needs_free_netdev isn't all that
necessary then?
So then the changes to net/mac80211/iface.c are just because you now
invoke priv_destructor in failure paths in register_netdevice, and that
would now double-free everything, since this was invoked already in the
failure paths - hence the change to only free the netdev in the failure
path.
I think you introduced a bug though - isn't this needed?
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1816,6 +1816,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
ret = dev_alloc_name(ndev, ndev->name);
if (ret < 0) {
ieee80211_if_free(ndev);
+ free_netdev(ndev);
return ret;
}
There was another caller of ieee80211_if_free() which you modified, and
thus needs the free_netdev() that you removed from it.
Would an alternative have been to not use (priv_)destructor here, and
just free all the data after unregister_netdevice(_many)? This sets the
reg_state to NETREG_UNREGISTERING, so sysfs can no longer look at the
stats afterwards, and it's been unlisted (unlist_netdevice) so can't be
reached through any other means either.
IOW, this would also work and fix the bug above along the way?
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 915d7e1b4545..23df973d5181 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1213,6 +1213,7 @@ static const struct net_device_ops ieee80211_monitorif_ops = {
static void ieee80211_if_free(struct net_device *dev)
{
free_percpu(dev->tstats);
+ free_netdev(dev);
}
static void ieee80211_if_setup(struct net_device *dev)
@@ -1220,8 +1221,6 @@ static void ieee80211_if_setup(struct net_device *dev)
ether_setup(dev);
dev->priv_flags &= ~IFF_TX_SKB_SHARING;
dev->netdev_ops = &ieee80211_dataif_ops;
- dev->needs_free_netdev = true;
- dev->priv_destructor = ieee80211_if_free;
}
static void ieee80211_if_setup_no_queue(struct net_device *dev)
@@ -1905,7 +1904,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
ret = register_netdevice(ndev);
if (ret) {
- free_netdev(ndev);
+ ieee80211_if_free(ndev);
return ret;
}
}
@@ -1932,6 +1931,7 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
if (sdata->dev) {
unregister_netdevice(sdata->dev);
+ ieee80211_if_free(sdata->dev);
} else {
cfg80211_unregister_wdev(&sdata->wdev);
ieee80211_teardown_sdata(sdata);
@@ -1950,7 +1950,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata, *tmp;
LIST_HEAD(unreg_list);
- LIST_HEAD(wdev_list);
ASSERT_RTNL();
@@ -1971,21 +1970,22 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
wiphy_name(local->hw.wiphy), local->open_count);
mutex_lock(&local->iflist_mtx);
- list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
- list_del(&sdata->list);
-
+ list_for_each_entry(sdata, &local->interfaces, list) {
if (sdata->dev)
unregister_netdevice_queue(sdata->dev, &unreg_list);
- else
- list_add(&sdata->list, &wdev_list);
}
mutex_unlock(&local->iflist_mtx);
unregister_netdevice_many(&unreg_list);
- list_for_each_entry_safe(sdata, tmp, &wdev_list, list) {
+ list_for_each_entry(sdata, &local->interfaces, list) {
list_del(&sdata->list);
- cfg80211_unregister_wdev(&sdata->wdev);
- kfree(sdata);
+
+ if (sdata->dev) {
+ ieee80211_if_free(sdata->dev);
+ } else {
+ cfg80211_unregister_wdev(&sdata->wdev);
+ kfree(sdata);
+ }
}
}
(I might be tempted to put that in to ease the backporting)
Thanks,
johannes
next prev parent reply other threads:[~2017-06-09 12:45 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-06-07 19:54 [PATCH] net: Fix inconsistent teardown and release of private netdev state David Miller
2017-06-09 12:45 ` Johannes Berg [this message]
2017-06-09 14:17 ` David Miller
2017-06-09 14:33 ` Johannes Berg
2017-06-09 17:14 ` David Miller
2017-06-09 17:21 ` Stephen Hemminger
2017-06-09 18:54 ` David Miller
2017-06-12 20:40 ` Stephen Hemminger
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1497012325.2424.12.camel@sipsolutions.net \
--to=johannes@sipsolutions.net \
--cc=davem@davemloft.net \
--cc=netdev@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).