[PATCH 3.2 010/115] mac80211: avoid excessive stack usage in sta_info

From: Ben Hutchings
Date: Tue Apr 26 2016 - 20:46:59 EST


3.2.80-rc1 review patch. If anyone has any objections, please let me know.

------------------

From: Arnd Bergmann <arnd@xxxxxxxx>

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@xxxxxxxx>
Fixes: 98b6218388e3 ("mac80211/cfg80211: add station events")
Fixes: 6f7a8d26e266 ("mac80211: send statistics with delete station event")
Signed-off-by: Johannes Berg <johannes.berg@xxxxxxxxx>
[bwh: Backported to 3.2:
- There's only one instance to fix
- Adjust context,indentation
- Use 'return' instead of 'goto out_err']
Signed-off-by: Ben Hutchings <ben@xxxxxxxxxxxxxxx>
---
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -344,12 +344,16 @@ static int sta_info_finish_insert(struct
{
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
- struct station_info sinfo;
+ struct station_info *sinfo;
unsigned long flags;
int err = 0;

lockdep_assert_held(&local->sta_mtx);

+ sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
+ if (!sinfo)
+ return -ENOMEM;
+
if (!sta->dummy || dummy_reinsert) {
/* notify driver */
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
@@ -397,12 +401,11 @@ static int sta_info_finish_insert(struct
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);
return 0;
}