Commit 3d529cd1 authored by Johannes Berg's avatar Johannes Berg

wifi: mac80211: use wiphy locked debugfs helpers for agg_status

The read is currently with RCU and the write can deadlock,
convert both for the sake of illustration.

Make mac80211 depend on cfg80211 debugfs to get the helpers,
but mac80211 debugfs without it does nothing anyway. This
also required some adjustments in ath9k.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent b590b9ae
...@@ -57,8 +57,7 @@ config ATH9K_AHB ...@@ -57,8 +57,7 @@ config ATH9K_AHB
config ATH9K_DEBUGFS config ATH9K_DEBUGFS
bool "Atheros ath9k debugging" bool "Atheros ath9k debugging"
depends on ATH9K && DEBUG_FS depends on ATH9K && DEBUG_FS && MAC80211_DEBUGFS
select MAC80211_DEBUGFS
select ATH9K_COMMON_DEBUG select ATH9K_COMMON_DEBUG
help help
Say Y, if you need access to ath9k's statistics for Say Y, if you need access to ath9k's statistics for
...@@ -70,7 +69,6 @@ config ATH9K_DEBUGFS ...@@ -70,7 +69,6 @@ config ATH9K_DEBUGFS
config ATH9K_STATION_STATISTICS config ATH9K_STATION_STATISTICS
bool "Detailed station statistics" bool "Detailed station statistics"
depends on ATH9K && ATH9K_DEBUGFS && DEBUG_FS depends on ATH9K && ATH9K_DEBUGFS && DEBUG_FS
select MAC80211_DEBUGFS
default n default n
help help
This option enables detailed statistics for association stations. This option enables detailed statistics for association stations.
......
...@@ -88,7 +88,7 @@ config MAC80211_LEDS ...@@ -88,7 +88,7 @@ config MAC80211_LEDS
config MAC80211_DEBUGFS config MAC80211_DEBUGFS
bool "Export mac80211 internals in DebugFS" bool "Export mac80211 internals in DebugFS"
depends on MAC80211 && DEBUG_FS depends on MAC80211 && CFG80211_DEBUGFS
help help
Select this to see extensive information about Select this to see extensive information about
the internal state of mac80211 in debugfs. the internal state of mac80211 in debugfs.
......
...@@ -312,23 +312,14 @@ static ssize_t sta_aql_write(struct file *file, const char __user *userbuf, ...@@ -312,23 +312,14 @@ static ssize_t sta_aql_write(struct file *file, const char __user *userbuf,
STA_OPS_RW(aql); STA_OPS_RW(aql);
static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, static ssize_t sta_agg_status_do_read(struct wiphy *wiphy, struct file *file,
size_t count, loff_t *ppos) char *buf, size_t bufsz, void *data)
{ {
char *buf, *p; struct sta_info *sta = data;
ssize_t bufsz = 71 + IEEE80211_NUM_TIDS * 40; char *p = buf;
int i; int i;
struct sta_info *sta = file->private_data;
struct tid_ampdu_rx *tid_rx; struct tid_ampdu_rx *tid_rx;
struct tid_ampdu_tx *tid_tx; struct tid_ampdu_tx *tid_tx;
ssize_t ret;
buf = kzalloc(bufsz, GFP_KERNEL);
if (!buf)
return -ENOMEM;
p = buf;
rcu_read_lock();
p += scnprintf(p, bufsz + buf - p, "next dialog_token: %#02x\n", p += scnprintf(p, bufsz + buf - p, "next dialog_token: %#02x\n",
sta->ampdu_mlme.dialog_token_allocator + 1); sta->ampdu_mlme.dialog_token_allocator + 1);
...@@ -338,8 +329,8 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, ...@@ -338,8 +329,8 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
for (i = 0; i < IEEE80211_NUM_TIDS; i++) { for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
bool tid_rx_valid; bool tid_rx_valid;
tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]); tid_rx = wiphy_dereference(wiphy, sta->ampdu_mlme.tid_rx[i]);
tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]); tid_tx = wiphy_dereference(wiphy, sta->ampdu_mlme.tid_tx[i]);
tid_rx_valid = test_bit(i, sta->ampdu_mlme.agg_session_valid); tid_rx_valid = test_bit(i, sta->ampdu_mlme.agg_session_valid);
p += scnprintf(p, bufsz + buf - p, "%02d", i); p += scnprintf(p, bufsz + buf - p, "%02d", i);
...@@ -358,31 +349,39 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, ...@@ -358,31 +349,39 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
tid_tx ? skb_queue_len(&tid_tx->pending) : 0); tid_tx ? skb_queue_len(&tid_tx->pending) : 0);
p += scnprintf(p, bufsz + buf - p, "\n"); p += scnprintf(p, bufsz + buf - p, "\n");
} }
rcu_read_unlock();
ret = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); return p - buf;
kfree(buf);
return ret;
} }
static ssize_t sta_agg_status_write(struct file *file, const char __user *userbuf, static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
char _buf[25] = {}, *buf = _buf;
struct sta_info *sta = file->private_data; struct sta_info *sta = file->private_data;
struct wiphy *wiphy = sta->local->hw.wiphy;
size_t bufsz = 71 + IEEE80211_NUM_TIDS * 40;
char *buf = kmalloc(bufsz, GFP_KERNEL);
ssize_t ret;
if (!buf)
return -ENOMEM;
ret = wiphy_locked_debugfs_read(wiphy, file, buf, bufsz,
userbuf, count, ppos,
sta_agg_status_do_read, sta);
kfree(buf);
return ret;
}
static ssize_t sta_agg_status_do_write(struct wiphy *wiphy, struct file *file,
char *buf, size_t count, void *data)
{
struct sta_info *sta = data;
bool start, tx; bool start, tx;
unsigned long tid; unsigned long tid;
char *pos; char *pos = buf;
int ret, timeout = 5000; int ret, timeout = 5000;
if (count > sizeof(_buf))
return -EINVAL;
if (copy_from_user(buf, userbuf, count))
return -EFAULT;
buf[sizeof(_buf) - 1] = '\0';
pos = buf;
buf = strsep(&pos, " "); buf = strsep(&pos, " ");
if (!buf) if (!buf)
return -EINVAL; return -EINVAL;
...@@ -420,7 +419,6 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu ...@@ -420,7 +419,6 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu
if (ret || tid >= IEEE80211_NUM_TIDS) if (ret || tid >= IEEE80211_NUM_TIDS)
return -EINVAL; return -EINVAL;
wiphy_lock(sta->local->hw.wiphy);
if (tx) { if (tx) {
if (start) if (start)
ret = ieee80211_start_tx_ba_session(&sta->sta, tid, ret = ieee80211_start_tx_ba_session(&sta->sta, tid,
...@@ -432,10 +430,22 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu ...@@ -432,10 +430,22 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu
3, true); 3, true);
ret = 0; ret = 0;
} }
wiphy_unlock(sta->local->hw.wiphy);
return ret ?: count; return ret ?: count;
} }
static ssize_t sta_agg_status_write(struct file *file,
const char __user *userbuf,
size_t count, loff_t *ppos)
{
struct sta_info *sta = file->private_data;
struct wiphy *wiphy = sta->local->hw.wiphy;
char _buf[26];
return wiphy_locked_debugfs_write(wiphy, file, _buf, sizeof(_buf),
userbuf, count,
sta_agg_status_do_write, sta);
}
STA_OPS_RW(agg_status); STA_OPS_RW(agg_status);
/* link sta attributes */ /* link sta attributes */
......
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