Commit 6c59578f authored by Arnd Bergmann's avatar Arnd Bergmann Committed by Sasha Levin

mac80211: avoid excessive stack usage in sta_info

[ Upstream commit 0ef049dc ]

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: default avatarArnd Bergmann <arnd@arndb.de>
Fixes: 98b62183 ("mac80211/cfg80211: add station events")
Fixes: 6f7a8d26 ("mac80211: send statistics with delete station event")
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarSasha Levin <sasha.levin@oracle.com>
parent f46752f2
...@@ -472,11 +472,17 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) ...@@ -472,11 +472,17 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
{ {
struct ieee80211_local *local = sta->local; struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_sub_if_data *sdata = sta->sdata;
struct station_info sinfo; struct station_info *sinfo;
int err = 0; int err = 0;
lockdep_assert_held(&local->sta_mtx); 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 */ /* check if STA exists already */
if (sta_info_get_bss(sdata, sta->sta.addr)) { if (sta_info_get_bss(sdata, sta->sta.addr)) {
err = -EEXIST; err = -EEXIST;
...@@ -510,10 +516,9 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) ...@@ -510,10 +516,9 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
ieee80211_sta_debugfs_add(sta); ieee80211_sta_debugfs_add(sta);
rate_control_add_sta_debugfs(sta); rate_control_add_sta_debugfs(sta);
memset(&sinfo, 0, sizeof(sinfo)); sinfo->generation = local->sta_generation;
sinfo.filled = 0; cfg80211_new_sta(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
sinfo.generation = local->sta_generation; kfree(sinfo);
cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL);
sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr); sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr);
...@@ -876,7 +881,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta) ...@@ -876,7 +881,7 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
{ {
struct ieee80211_local *local = sta->local; struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_sub_if_data *sdata = sta->sdata;
struct station_info sinfo = {}; struct station_info *sinfo;
int ret; int ret;
/* /*
...@@ -914,8 +919,11 @@ static void __sta_info_destroy_part2(struct sta_info *sta) ...@@ -914,8 +919,11 @@ static void __sta_info_destroy_part2(struct sta_info *sta)
sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr);
sta_set_sinfo(sta, &sinfo); sinfo = kzalloc(sizeof(*sinfo), GFP_KERNEL);
cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); if (sinfo)
sta_set_sinfo(sta, sinfo);
cfg80211_del_sta_sinfo(sdata->dev, sta->sta.addr, sinfo, GFP_KERNEL);
kfree(sinfo);
rate_control_remove_sta_debugfs(sta); rate_control_remove_sta_debugfs(sta);
ieee80211_sta_debugfs_remove(sta); ieee80211_sta_debugfs_remove(sta);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment