wifi: mac80211: use wiphy locked debugfs for sdata/link

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>
This commit is contained in:
Johannes Berg 2023-11-24 17:25:29 +01:00
parent 3d529cd11f
commit 4ded3bfe1d
1 changed files with 105 additions and 45 deletions

View File

@ -22,88 +22,148 @@
#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;
};
return ret;
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 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);
}
if (ret >= 0)
ret = simple_read_from_buffer(userbuf, count, ppos, buf, ret);
struct ieee80211_if_write_link_data {
ssize_t (*write)(struct ieee80211_link_data *, const char *, int);
struct ieee80211_link_data *link;
};
return 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 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); \
}