| From be1786748a3d1590e2f53eaf8fff3d20313e4f63 Mon Sep 17 00:00:00 2001 |
| From: Johannes Berg <johannes.berg@intel.com> |
| Date: Thu, 23 Apr 2020 11:13:49 +0200 |
| Subject: [PATCH] mac80211: populate debugfs only after cfg80211 init |
| |
| commit 6cb5f3ea4654faf8c28b901266e960b1a4787b26 upstream. |
| |
| When fixing the initialization race, we neglected to account for |
| the fact that debugfs is initialized in wiphy_register(), and |
| some debugfs things went missing (or rather were rerooted to the |
| global debugfs root). |
| |
| Fix this by adding debugfs entries only after wiphy_register(). |
| This requires some changes in the rate control code since it |
| currently adds debugfs at alloc time, which can no longer be |
| done after the reordering. |
| |
| Reported-by: Jouni Malinen <j@w1.fi> |
| Reported-by: kernel test robot <rong.a.chen@intel.com> |
| Reported-by: Hauke Mehrtens <hauke@hauke-m.de> |
| Reported-by: Felix Fietkau <nbd@nbd.name> |
| Cc: stable@vger.kernel.org |
| Fixes: 52e04b4ce5d0 ("mac80211: fix race in ieee80211_register_hw()") |
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> |
| Acked-by: Sumit Garg <sumit.garg@linaro.org> |
| Link: https://lore.kernel.org/r/20200423111344.0e00d3346f12.Iadc76a03a55093d94391fc672e996a458702875d@changeid |
| Signed-off-by: Johannes Berg <johannes.berg@intel.com> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| diff --git a/drivers/net/wireless/intel/iwlegacy/3945-rs.c b/drivers/net/wireless/intel/iwlegacy/3945-rs.c |
| index 5bd8a9ee8b1e..602f3b3e6c47 100644 |
| --- a/drivers/net/wireless/intel/iwlegacy/3945-rs.c |
| +++ b/drivers/net/wireless/intel/iwlegacy/3945-rs.c |
| @@ -374,7 +374,7 @@ il3945_rs_rate_init(struct il_priv *il, struct ieee80211_sta *sta, u8 sta_id) |
| } |
| |
| static void * |
| -il3945_rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
| +il3945_rs_alloc(struct ieee80211_hw *hw) |
| { |
| return hw->priv; |
| } |
| diff --git a/drivers/net/wireless/intel/iwlegacy/4965-rs.c b/drivers/net/wireless/intel/iwlegacy/4965-rs.c |
| index a824a10a43b6..ba3069bce935 100644 |
| --- a/drivers/net/wireless/intel/iwlegacy/4965-rs.c |
| +++ b/drivers/net/wireless/intel/iwlegacy/4965-rs.c |
| @@ -2478,7 +2478,7 @@ il4965_rs_fill_link_cmd(struct il_priv *il, struct il_lq_sta *lq_sta, |
| } |
| |
| static void * |
| -il4965_rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
| +il4965_rs_alloc(struct ieee80211_hw *hw) |
| { |
| return hw->priv; |
| } |
| diff --git a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c |
| index b500c9279a32..2ac498d2852c 100644 |
| --- a/drivers/net/wireless/intel/iwlwifi/dvm/rs.c |
| +++ b/drivers/net/wireless/intel/iwlwifi/dvm/rs.c |
| @@ -3023,7 +3023,7 @@ static void rs_fill_link_cmd(struct iwl_priv *priv, |
| cpu_to_le16(priv->lib->bt_params->agg_time_limit); |
| } |
| |
| -static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
| +static void *rs_alloc(struct ieee80211_hw *hw) |
| { |
| return hw->priv; |
| } |
| diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c |
| index 01b032f18bc8..bd6a571b3e28 100644 |
| --- a/drivers/net/wireless/intel/iwlwifi/mvm/rs.c |
| +++ b/drivers/net/wireless/intel/iwlwifi/mvm/rs.c |
| @@ -3667,7 +3667,7 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm, |
| cpu_to_le16(iwl_mvm_coex_agg_time_limit(mvm, sta)); |
| } |
| |
| -static void *rs_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
| +static void *rs_alloc(struct ieee80211_hw *hw) |
| { |
| return hw->priv; |
| } |
| diff --git a/drivers/net/wireless/realtek/rtlwifi/rc.c b/drivers/net/wireless/realtek/rtlwifi/rc.c |
| index cf8e42a01015..ceb2283ee036 100644 |
| --- a/drivers/net/wireless/realtek/rtlwifi/rc.c |
| +++ b/drivers/net/wireless/realtek/rtlwifi/rc.c |
| @@ -264,7 +264,7 @@ static void rtl_rate_update(void *ppriv, |
| { |
| } |
| |
| -static void *rtl_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
| +static void *rtl_rate_alloc(struct ieee80211_hw *hw) |
| { |
| struct rtl_priv *rtlpriv = rtl_priv(hw); |
| return rtlpriv; |
| diff --git a/include/net/mac80211.h b/include/net/mac80211.h |
| index 456f2edf78dc..3a8e445257cd 100644 |
| --- a/include/net/mac80211.h |
| +++ b/include/net/mac80211.h |
| @@ -5911,7 +5911,9 @@ enum rate_control_capabilities { |
| struct rate_control_ops { |
| unsigned long capa; |
| const char *name; |
| - void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir); |
| + void *(*alloc)(struct ieee80211_hw *hw); |
| + void (*add_debugfs)(struct ieee80211_hw *hw, void *priv, |
| + struct dentry *debugfsdir); |
| void (*free)(void *priv); |
| |
| void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp); |
| diff --git a/net/mac80211/main.c b/net/mac80211/main.c |
| index 3deb1a45a3e1..27045a9b4785 100644 |
| --- a/net/mac80211/main.c |
| +++ b/net/mac80211/main.c |
| @@ -1160,8 +1160,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) |
| local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom, |
| IEEE80211_TX_STATUS_HEADROOM); |
| |
| - debugfs_hw_add(local); |
| - |
| /* |
| * if the driver doesn't specify a max listen interval we |
| * use 5 which should be a safe default |
| @@ -1253,6 +1251,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) |
| if (result < 0) |
| goto fail_wiphy_register; |
| |
| + debugfs_hw_add(local); |
| + rate_control_add_debugfs(local); |
| + |
| rtnl_lock(); |
| |
| /* add one default STA interface if supported */ |
| diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c |
| index 47ee36677c2b..39954e77aaca 100644 |
| --- a/net/mac80211/rate.c |
| +++ b/net/mac80211/rate.c |
| @@ -214,17 +214,16 @@ static ssize_t rcname_read(struct file *file, char __user *userbuf, |
| ref->ops->name, len); |
| } |
| |
| -static const struct file_operations rcname_ops = { |
| +const struct file_operations rcname_ops = { |
| .read = rcname_read, |
| .open = simple_open, |
| .llseek = default_llseek, |
| }; |
| #endif |
| |
| -static struct rate_control_ref *rate_control_alloc(const char *name, |
| - struct ieee80211_local *local) |
| +static struct rate_control_ref * |
| +rate_control_alloc(const char *name, struct ieee80211_local *local) |
| { |
| - struct dentry *debugfsdir = NULL; |
| struct rate_control_ref *ref; |
| |
| ref = kmalloc(sizeof(struct rate_control_ref), GFP_KERNEL); |
| @@ -234,13 +233,7 @@ static struct rate_control_ref *rate_control_alloc(const char *name, |
| if (!ref->ops) |
| goto free; |
| |
| -#ifdef CONFIG_MAC80211_DEBUGFS |
| - debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir); |
| - local->debugfs.rcdir = debugfsdir; |
| - debugfs_create_file("name", 0400, debugfsdir, ref, &rcname_ops); |
| -#endif |
| - |
| - ref->priv = ref->ops->alloc(&local->hw, debugfsdir); |
| + ref->priv = ref->ops->alloc(&local->hw); |
| if (!ref->priv) |
| goto free; |
| return ref; |
| diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h |
| index 5d5348bc41ec..db96d2da5c55 100644 |
| --- a/net/mac80211/rate.h |
| +++ b/net/mac80211/rate.h |
| @@ -69,6 +69,29 @@ static inline void rate_control_remove_sta_debugfs(struct sta_info *sta) |
| #endif |
| } |
| |
| +extern const struct file_operations rcname_ops; |
| + |
| +static inline void rate_control_add_debugfs(struct ieee80211_local *local) |
| +{ |
| +#ifdef CONFIG_MAC80211_DEBUGFS |
| + struct dentry *debugfsdir; |
| + |
| + if (!local->rate_ctrl) |
| + return; |
| + |
| + if (!local->rate_ctrl->ops->add_debugfs) |
| + return; |
| + |
| + debugfsdir = debugfs_create_dir("rc", local->hw.wiphy->debugfsdir); |
| + local->debugfs.rcdir = debugfsdir; |
| + debugfs_create_file("name", 0400, debugfsdir, |
| + local->rate_ctrl, &rcname_ops); |
| + |
| + local->rate_ctrl->ops->add_debugfs(&local->hw, local->rate_ctrl->priv, |
| + debugfsdir); |
| +#endif |
| +} |
| + |
| void ieee80211_check_rate_mask(struct ieee80211_sub_if_data *sdata); |
| |
| /* Get a reference to the rate control algorithm. If `name' is NULL, get the |
| diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c |
| index 298a1acb3ce5..1c5e843dede2 100644 |
| --- a/net/mac80211/rc80211_minstrel_ht.c |
| +++ b/net/mac80211/rc80211_minstrel_ht.c |
| @@ -1431,7 +1431,7 @@ minstrel_ht_init_cck_rates(struct minstrel_priv *mp) |
| } |
| |
| static void * |
| -minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
| +minstrel_ht_alloc(struct ieee80211_hw *hw) |
| { |
| struct minstrel_priv *mp; |
| |
| @@ -1466,16 +1466,22 @@ minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) |
| mp->hw = hw; |
| mp->update_interval = 100; |
| |
| + minstrel_ht_init_cck_rates(mp); |
| + |
| + return mp; |
| +} |
| + |
| #ifdef CONFIG_MAC80211_DEBUGFS |
| +static void minstrel_ht_add_debugfs(struct ieee80211_hw *hw, void *priv, |
| + struct dentry *debugfsdir) |
| +{ |
| + struct minstrel_priv *mp = priv; |
| + |
| mp->fixed_rate_idx = (u32) -1; |
| debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir, |
| &mp->fixed_rate_idx); |
| -#endif |
| - |
| - minstrel_ht_init_cck_rates(mp); |
| - |
| - return mp; |
| } |
| +#endif |
| |
| static void |
| minstrel_ht_free(void *priv) |
| @@ -1514,6 +1520,7 @@ static const struct rate_control_ops mac80211_minstrel_ht = { |
| .alloc = minstrel_ht_alloc, |
| .free = minstrel_ht_free, |
| #ifdef CONFIG_MAC80211_DEBUGFS |
| + .add_debugfs = minstrel_ht_add_debugfs, |
| .add_sta_debugfs = minstrel_ht_add_sta_debugfs, |
| #endif |
| .get_expected_throughput = minstrel_ht_get_expected_throughput, |
| -- |
| 2.7.4 |
| |