diff options
author | Arnd Bergmann <arnd@arndb.de> | 2016-01-27 01:05:31 +0300 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2016-05-01 01:05:50 +0300 |
commit | ad86e29c3b2f2f9deefb7155f96fd9d8e5d42a75 (patch) | |
tree | 3dcff5c3a70489f0e4a3092f5c38de0cec221ac7 | |
parent | 5f1842be6e3affe8e8ee2b970b1fa4bb77a1d3ff (diff) | |
download | linux-ad86e29c3b2f2f9deefb7155f96fd9d8e5d42a75.tar.xz |
mac80211: avoid excessive stack usage in sta_info
commit 0ef049dc1167fe834d0ad5d63f89eddc5c70f6e4 upstream.
When CONFIG_OPTIMIZE_INLINING is set, the sta_info_insert_finish
function consumes more stack than normally, exceeding the
1024 byte limit on ARM:
net/mac80211/sta_info.c: In function 'sta_info_insert_finish':
net/mac80211/sta_info.c:561:1: error: the frame size of 1080 bytes is larger than 1024 bytes [-Werror=frame-larger-than=]
It turns out that there are two functions that put a 'struct station_info'
on the stack: __sta_info_destroy_part2 and sta_info_insert_finish, and
this structure alone requires up to 792 bytes.
Hoping that both are called rarely enough, this replaces the
on-stack structure with a dynamic allocation, which unfortunately
requires some suboptimal error handling for out-of-memory.
The __sta_info_destroy_part2 function is actually affected by the
stack usage twice because it calls cfg80211_del_sta_sinfo(), which
has another instance of struct station_info on its stack.
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
Fixes: 98b6218388e3 ("mac80211/cfg80211: add station events")
Fixes: 6f7a8d26e266 ("mac80211: send statistics with delete station event")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
[bwh: Backported to 3.16: there's only one instance to fix]
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
-rw-r--r-- | net/mac80211/sta_info.c | 15 |
1 files changed, 10 insertions, 5 deletions
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index a9b46d8ea22f..81cd2e7f1e7d 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -487,11 +487,17 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) { struct ieee80211_local *local = sta->local; struct ieee80211_sub_if_data *sdata = sta->sdata; - struct station_info sinfo; + struct station_info *sinfo; int err = 0; lockdep_assert_held(&local->sta_mtx); + sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL); + if (!sinfo) { + err = -ENOMEM; + goto out_err; + } + /* check if STA exists already */ if (sta_info_get_bss(sdata, sta->sta.addr)) { err = -EEXIST; @@ -523,10 +529,9 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) ieee80211_sta_debugfs_add(sta); rate_control_add_sta_debugfs(sta); - memset(&sinfo, 0, sizeof(sinfo)); - sinfo.filled = 0; - sinfo.generation = local->sta_generation; - cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); + sinfo->generation = local->sta_generation; + cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL); + kfree(sinfo); sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr); |