]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
wifi: mac80211: use wiphy locked debugfs helpers for agg_status
authorJohannes Berg <johannes.berg@intel.com>
Fri, 24 Nov 2023 16:25:28 +0000 (17:25 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 27 Nov 2023 10:25:01 +0000 (11:25 +0100)
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: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/ath/ath9k/Kconfig
net/mac80211/Kconfig
net/mac80211/debugfs_sta.c

index e150d82eddb6c72859872abc7b3d7e73b7484e94..0c47be06c153be18c410324a62f12c77264b38b9 100644 (file)
@@ -57,8 +57,7 @@ config ATH9K_AHB
 
 config ATH9K_DEBUGFS
        bool "Atheros ath9k debugging"
-       depends on ATH9K && DEBUG_FS
-       select MAC80211_DEBUGFS
+       depends on ATH9K && DEBUG_FS && MAC80211_DEBUGFS
        select ATH9K_COMMON_DEBUG
        help
          Say Y, if you need access to ath9k's statistics for
@@ -70,7 +69,6 @@ config ATH9K_DEBUGFS
 config ATH9K_STATION_STATISTICS
        bool "Detailed station statistics"
        depends on ATH9K && ATH9K_DEBUGFS && DEBUG_FS
-       select MAC80211_DEBUGFS
        default n
        help
          This option enables detailed statistics for association stations.
index 037ab74f5ade5b1961ff7292c4113f7aae4ef2d2..cb0291decf2e56c7d4111e649f41d28577af987e 100644 (file)
@@ -88,7 +88,7 @@ config MAC80211_LEDS
 
 config MAC80211_DEBUGFS
        bool "Export mac80211 internals in DebugFS"
-       depends on MAC80211 && DEBUG_FS
+       depends on MAC80211 && CFG80211_DEBUGFS
        help
          Select this to see extensive information about
          the internal state of mac80211 in debugfs.
index 06e3613bf46bd918a69ff3d50cfa1411d466e4a8..5bf507ebb096be315ceb13162a761e20134c3434 100644 (file)
@@ -312,23 +312,14 @@ static ssize_t sta_aql_write(struct file *file, const char __user *userbuf,
 STA_OPS_RW(aql);
 
 
-static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
-                                       size_t count, loff_t *ppos)
+static ssize_t sta_agg_status_do_read(struct wiphy *wiphy, struct file *file,
+                                     char *buf, size_t bufsz, void *data)
 {
-       char *buf, *p;
-       ssize_t bufsz = 71 + IEEE80211_NUM_TIDS * 40;
+       struct sta_info *sta = data;
+       char *p = buf;
        int i;
-       struct sta_info *sta = file->private_data;
        struct tid_ampdu_rx *tid_rx;
        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",
                        sta->ampdu_mlme.dialog_token_allocator + 1);
@@ -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++) {
                bool tid_rx_valid;
 
-               tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]);
-               tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]);
+               tid_rx = wiphy_dereference(wiphy, sta->ampdu_mlme.tid_rx[i]);
+               tid_tx = wiphy_dereference(wiphy, sta->ampdu_mlme.tid_tx[i]);
                tid_rx_valid = test_bit(i, sta->ampdu_mlme.agg_session_valid);
 
                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,
                                tid_tx ? skb_queue_len(&tid_tx->pending) : 0);
                p += scnprintf(p, bufsz + buf - p, "\n");
        }
-       rcu_read_unlock();
 
-       ret = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+       return p - buf;
+}
+
+static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
+                                  size_t count, loff_t *ppos)
+{
+       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_write(struct file *file, const char __user *userbuf,
-                                   size_t count, loff_t *ppos)
+static ssize_t sta_agg_status_do_write(struct wiphy *wiphy, struct file *file,
+                                      char *buf, size_t count, void *data)
 {
-       char _buf[25] = {}, *buf = _buf;
-       struct sta_info *sta = file->private_data;
+       struct sta_info *sta = data;
        bool start, tx;
        unsigned long tid;
-       char *pos;
+       char *pos = buf;
        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, " ");
        if (!buf)
                return -EINVAL;
@@ -420,7 +419,6 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu
        if (ret || tid >= IEEE80211_NUM_TIDS)
                return -EINVAL;
 
-       wiphy_lock(sta->local->hw.wiphy);
        if (tx) {
                if (start)
                        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
                                               3, true);
                ret = 0;
        }
-       wiphy_unlock(sta->local->hw.wiphy);
 
        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);
 
 /* link sta attributes */