wifi: mac80211: use wiphy locked debugfs for sdata/link
authorJohannes Berg <johannes.berg@intel.com>
Fri, 24 Nov 2023 16:25:29 +0000 (17:25 +0100)
committerJohannes Berg <johannes.berg@intel.com>
Mon, 27 Nov 2023 10:25:09 +0000 (11:25 +0100)
The debugfs files for netdevs (sdata) and links are removed
with the wiphy mutex held, which may deadlock. Use the new
wiphy locked debugfs to avoid that.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
net/mac80211/debugfs_netdev.c

index ec91e131b29e5aa8e5e2baf177819fcf6d973fe0..80aeb25f1b68d1e63e2aca0049258a2524848675 100644 (file)
 #include "debugfs_netdev.h"
 #include "driver-ops.h"
 
+struct ieee80211_if_read_sdata_data {
+       ssize_t (*format)(const struct ieee80211_sub_if_data *, char *, int);
+       struct ieee80211_sub_if_data *sdata;
+};
+
+static ssize_t ieee80211_if_read_sdata_handler(struct wiphy *wiphy,
+                                              struct file *file,
+                                              char *buf,
+                                              size_t bufsize,
+                                              void *data)
+{
+       struct ieee80211_if_read_sdata_data *d = data;
+
+       return d->format(d->sdata, buf, bufsize);
+}
+
 static ssize_t ieee80211_if_read_sdata(
-       struct ieee80211_sub_if_data *sdata,
+       struct file *file,
        char __user *userbuf,
        size_t count, loff_t *ppos,
        ssize_t (*format)(const struct ieee80211_sub_if_data *sdata, char *, int))
 {
+       struct ieee80211_sub_if_data *sdata = file->private_data;
+       struct ieee80211_if_read_sdata_data data = {
+               .format = format,
+               .sdata = sdata,
+       };
        char buf[200];
-       ssize_t ret = -EINVAL;
 
-       wiphy_lock(sdata->local->hw.wiphy);
-       ret = (*format)(sdata, buf, sizeof(buf));
-       wiphy_unlock(sdata->local->hw.wiphy);
+       return wiphy_locked_debugfs_read(sdata->local->hw.wiphy,
+                                        file, buf, sizeof(buf),
+                                        userbuf, count, ppos,
+                                        ieee80211_if_read_sdata_handler,
+                                        &data);
+}
 
-       if (ret >= 0)
-               ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+struct ieee80211_if_write_sdata_data {
+       ssize_t (*write)(struct ieee80211_sub_if_data *, const char *, int);
+       struct ieee80211_sub_if_data *sdata;
+};
+
+static ssize_t ieee80211_if_write_sdata_handler(struct wiphy *wiphy,
+                                               struct file *file,
+                                               char *buf,
+                                               size_t count,
+                                               void *data)
+{
+       struct ieee80211_if_write_sdata_data *d = data;
 
-       return ret;
+       return d->write(d->sdata, buf, count);
 }
 
 static ssize_t ieee80211_if_write_sdata(
-       struct ieee80211_sub_if_data *sdata,
+       struct file *file,
        const char __user *userbuf,
        size_t count, loff_t *ppos,
        ssize_t (*write)(struct ieee80211_sub_if_data *sdata, const char *, int))
 {
+       struct ieee80211_sub_if_data *sdata = file->private_data;
+       struct ieee80211_if_write_sdata_data data = {
+               .write = write,
+               .sdata = sdata,
+       };
        char buf[64];
-       ssize_t ret;
 
-       if (count >= sizeof(buf))
-               return -E2BIG;
+       return wiphy_locked_debugfs_write(sdata->local->hw.wiphy,
+                                         file, buf, sizeof(buf),
+                                         userbuf, count,
+                                         ieee80211_if_write_sdata_handler,
+                                         &data);
+}
 
-       if (copy_from_user(buf, userbuf, count))
-               return -EFAULT;
-       buf[count] = '\0';
+struct ieee80211_if_read_link_data {
+       ssize_t (*format)(const struct ieee80211_link_data *, char *, int);
+       struct ieee80211_link_data *link;
+};
 
-       wiphy_lock(sdata->local->hw.wiphy);
-       ret = (*write)(sdata, buf, count);
-       wiphy_unlock(sdata->local->hw.wiphy);
+static ssize_t ieee80211_if_read_link_handler(struct wiphy *wiphy,
+                                             struct file *file,
+                                             char *buf,
+                                             size_t bufsize,
+                                             void *data)
+{
+       struct ieee80211_if_read_link_data *d = data;
 
-       return ret;
+       return d->format(d->link, buf, bufsize);
 }
 
 static ssize_t ieee80211_if_read_link(
-       struct ieee80211_link_data *link,
+       struct file *file,
        char __user *userbuf,
        size_t count, loff_t *ppos,
        ssize_t (*format)(const struct ieee80211_link_data *link, char *, int))
 {
+       struct ieee80211_link_data *link = file->private_data;
+       struct ieee80211_if_read_link_data data = {
+               .format = format,
+               .link = link,
+       };
        char buf[200];
-       ssize_t ret = -EINVAL;
 
-       wiphy_lock(link->sdata->local->hw.wiphy);
-       ret = (*format)(link, buf, sizeof(buf));
-       wiphy_unlock(link->sdata->local->hw.wiphy);
+       return wiphy_locked_debugfs_read(link->sdata->local->hw.wiphy,
+                                        file, buf, sizeof(buf),
+                                        userbuf, count, ppos,
+                                        ieee80211_if_read_link_handler,
+                                        &data);
+}
+
+struct ieee80211_if_write_link_data {
+       ssize_t (*write)(struct ieee80211_link_data *, const char *, int);
+       struct ieee80211_link_data *link;
+};
 
-       if (ret >= 0)
-               ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
+static ssize_t ieee80211_if_write_link_handler(struct wiphy *wiphy,
+                                              struct file *file,
+                                              char *buf,
+                                              size_t count,
+                                              void *data)
+{
+       struct ieee80211_if_write_sdata_data *d = data;
 
-       return ret;
+       return d->write(d->sdata, buf, count);
 }
 
 static ssize_t ieee80211_if_write_link(
-       struct ieee80211_link_data *link,
+       struct file *file,
        const char __user *userbuf,
        size_t count, loff_t *ppos,
        ssize_t (*write)(struct ieee80211_link_data *link, const char *, int))
 {
+       struct ieee80211_link_data *link = file->private_data;
+       struct ieee80211_if_write_link_data data = {
+               .write = write,
+               .link = link,
+       };
        char buf[64];
-       ssize_t ret;
-
-       if (count >= sizeof(buf))
-               return -E2BIG;
-
-       if (copy_from_user(buf, userbuf, count))
-               return -EFAULT;
-       buf[count] = '\0';
-
-       wiphy_lock(link->sdata->local->hw.wiphy);
-       ret = (*write)(link, buf, count);
-       wiphy_unlock(link->sdata->local->hw.wiphy);
 
-       return ret;
+       return wiphy_locked_debugfs_write(link->sdata->local->hw.wiphy,
+                                         file, buf, sizeof(buf),
+                                         userbuf, count,
+                                         ieee80211_if_write_link_handler,
+                                         &data);
 }
 
 #define IEEE80211_IF_FMT(name, type, field, format_string)             \
@@ -173,7 +233,7 @@ static ssize_t ieee80211_if_read_##name(struct file *file,          \
                                        char __user *userbuf,           \
                                        size_t count, loff_t *ppos)     \
 {                                                                      \
-       return ieee80211_if_read_sdata(file->private_data,              \
+       return ieee80211_if_read_sdata(file,                            \
                                       userbuf, count, ppos,            \
                                       ieee80211_if_fmt_##name);        \
 }
@@ -183,7 +243,7 @@ static ssize_t ieee80211_if_write_##name(struct file *file,         \
                                         const char __user *userbuf,    \
                                         size_t count, loff_t *ppos)    \
 {                                                                      \
-       return ieee80211_if_write_sdata(file->private_data, userbuf,    \
+       return ieee80211_if_write_sdata(file, userbuf,                  \
                                        count, ppos,                    \
                                        ieee80211_if_parse_##name);     \
 }
@@ -211,7 +271,7 @@ static ssize_t ieee80211_if_read_##name(struct file *file,          \
                                        char __user *userbuf,           \
                                        size_t count, loff_t *ppos)     \
 {                                                                      \
-       return ieee80211_if_read_link(file->private_data,               \
+       return ieee80211_if_read_link(file,                             \
                                      userbuf, count, ppos,             \
                                      ieee80211_if_fmt_##name); \
 }
@@ -221,7 +281,7 @@ static ssize_t ieee80211_if_write_##name(struct file *file,         \
                                         const char __user *userbuf,    \
                                         size_t count, loff_t *ppos)    \
 {                                                                      \
-       return ieee80211_if_write_link(file->private_data, userbuf,     \
+       return ieee80211_if_write_link(file, userbuf,                   \
                                       count, ppos,                     \
                                       ieee80211_if_parse_##name);      \
 }