Commit 4ded3bfe authored by Johannes Berg's avatar Johannes Berg
Browse files

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: default avatarJohannes Berg <johannes.berg@intel.com>
parent 3d529cd1
Loading
Loading
Loading
Loading
+105 −45
Original line number Diff line number Diff line
@@ -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);	\
}