Skip to content

Commit 300fbb2

Browse files
committed
Merge tag 'wireless-2023-11-29' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless
Johannes Berg says: ==================== wireless fixes: - debugfs had a deadlock (removal vs. use of files), fixes going through wireless ACKed by Greg - support for HT STAs on 320 MHz channels, even if it's not clear that should ever happen (that's 6 GHz), best not to WARN() - fix for the previous CQM fix that broke most cases - various wiphy locking fixes - various small driver fixes * tag 'wireless-2023-11-29' of git://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless: wifi: mac80211: use wiphy locked debugfs for sdata/link wifi: mac80211: use wiphy locked debugfs helpers for agg_status wifi: cfg80211: add locked debugfs wrappers debugfs: add API to allow debugfs operations cancellation debugfs: annotate debugfs handlers vs. removal with lockdep debugfs: fix automount d_fsdata usage wifi: mac80211: handle 320 MHz in ieee80211_ht_cap_ie_to_sta_ht_cap wifi: avoid offset calculation on NULL pointer wifi: cfg80211: hold wiphy mutex for send_interface wifi: cfg80211: lock wiphy mutex for rfkill poll wifi: cfg80211: fix CQM for non-range use wifi: mac80211: do not pass AP_VLAN vif pointer to drivers during flush wifi: iwlwifi: mvm: fix an error code in iwl_mvm_mld_add_sta() wifi: mt76: mt7925: fix typo in mt7925_init_he_caps wifi: mt76: mt7921: fix 6GHz disabled by the missing default CLC config ==================== Link: https://lore.kernel.org/r/20231129150809.31083-3-johannes@sipsolutions.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 0d47fa5 + 4ded3bf commit 300fbb2

19 files changed

Lines changed: 614 additions & 118 deletions

File tree

drivers/net/wireless/ath/ath9k/Kconfig

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ config ATH9K_AHB
5757

5858
config ATH9K_DEBUGFS
5959
bool "Atheros ath9k debugging"
60-
depends on ATH9K && DEBUG_FS
61-
select MAC80211_DEBUGFS
60+
depends on ATH9K && DEBUG_FS && MAC80211_DEBUGFS
6261
select ATH9K_COMMON_DEBUG
6362
help
6463
Say Y, if you need access to ath9k's statistics for
@@ -70,7 +69,6 @@ config ATH9K_DEBUGFS
7069
config ATH9K_STATION_STATISTICS
7170
bool "Detailed station statistics"
7271
depends on ATH9K && ATH9K_DEBUGFS && DEBUG_FS
73-
select MAC80211_DEBUGFS
7472
default n
7573
help
7674
This option enables detailed statistics for association stations.

drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,8 +707,10 @@ int iwl_mvm_mld_add_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
707707
rcu_dereference_protected(mvm_sta->link[link_id],
708708
lockdep_is_held(&mvm->mutex));
709709

710-
if (WARN_ON(!link_conf || !mvm_link_sta))
710+
if (WARN_ON(!link_conf || !mvm_link_sta)) {
711+
ret = -EINVAL;
711712
goto err;
713+
}
712714

713715
ret = iwl_mvm_mld_cfg_sta(mvm, sta, vif, link_sta, link_conf,
714716
mvm_link_sta);

drivers/net/wireless/mediatek/mt76/mt7921/mcu.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,7 @@ static int mt7921_load_clc(struct mt792x_dev *dev, const char *fw_name)
375375
int ret, i, len, offset = 0;
376376
u8 *clc_base = NULL, hw_encap = 0;
377377

378+
dev->phy.clc_chan_conf = 0xff;
378379
if (mt7921_disable_clc ||
379380
mt76_is_usb(&dev->mt76))
380381
return 0;

drivers/net/wireless/mediatek/mt76/mt7925/main.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
static void
1515
mt7925_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band,
1616
struct ieee80211_sband_iftype_data *data,
17-
enum nl80211_iftype iftype)
17+
enum nl80211_iftype iftype)
1818
{
1919
struct ieee80211_sta_he_cap *he_cap = &data->he_cap;
2020
struct ieee80211_he_cap_elem *he_cap_elem = &he_cap->he_cap_elem;
@@ -53,7 +53,7 @@ mt7925_init_he_caps(struct mt792x_phy *phy, enum nl80211_band band,
5353
IEEE80211_HE_PHY_CAP2_UL_MU_FULL_MU_MIMO |
5454
IEEE80211_HE_PHY_CAP2_UL_MU_PARTIAL_MU_MIMO;
5555

56-
switch (i) {
56+
switch (iftype) {
5757
case NL80211_IFTYPE_AP:
5858
he_cap_elem->mac_cap_info[2] |=
5959
IEEE80211_HE_MAC_CAP2_BSR;

fs/debugfs/file.c

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,14 @@ int debugfs_file_get(struct dentry *dentry)
8484
struct debugfs_fsdata *fsd;
8585
void *d_fsd;
8686

87+
/*
88+
* This could only happen if some debugfs user erroneously calls
89+
* debugfs_file_get() on a dentry that isn't even a file, let
90+
* them know about it.
91+
*/
92+
if (WARN_ON(!d_is_reg(dentry)))
93+
return -EINVAL;
94+
8795
d_fsd = READ_ONCE(dentry->d_fsdata);
8896
if (!((unsigned long)d_fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)) {
8997
fsd = d_fsd;
@@ -100,6 +108,14 @@ int debugfs_file_get(struct dentry *dentry)
100108
kfree(fsd);
101109
fsd = READ_ONCE(dentry->d_fsdata);
102110
}
111+
#ifdef CONFIG_LOCKDEP
112+
fsd->lock_name = kasprintf(GFP_KERNEL, "debugfs:%pd", dentry);
113+
lockdep_register_key(&fsd->key);
114+
lockdep_init_map(&fsd->lockdep_map, fsd->lock_name ?: "debugfs",
115+
&fsd->key, 0);
116+
#endif
117+
INIT_LIST_HEAD(&fsd->cancellations);
118+
mutex_init(&fsd->cancellations_mtx);
103119
}
104120

105121
/*
@@ -116,6 +132,8 @@ int debugfs_file_get(struct dentry *dentry)
116132
if (!refcount_inc_not_zero(&fsd->active_users))
117133
return -EIO;
118134

135+
lock_map_acquire_read(&fsd->lockdep_map);
136+
119137
return 0;
120138
}
121139
EXPORT_SYMBOL_GPL(debugfs_file_get);
@@ -133,11 +151,93 @@ void debugfs_file_put(struct dentry *dentry)
133151
{
134152
struct debugfs_fsdata *fsd = READ_ONCE(dentry->d_fsdata);
135153

154+
lock_map_release(&fsd->lockdep_map);
155+
136156
if (refcount_dec_and_test(&fsd->active_users))
137157
complete(&fsd->active_users_drained);
138158
}
139159
EXPORT_SYMBOL_GPL(debugfs_file_put);
140160

161+
/**
162+
* debugfs_enter_cancellation - enter a debugfs cancellation
163+
* @file: the file being accessed
164+
* @cancellation: the cancellation object, the cancel callback
165+
* inside of it must be initialized
166+
*
167+
* When a debugfs file is removed it needs to wait for all active
168+
* operations to complete. However, the operation itself may need
169+
* to wait for hardware or completion of some asynchronous process
170+
* or similar. As such, it may need to be cancelled to avoid long
171+
* waits or even deadlocks.
172+
*
173+
* This function can be used inside a debugfs handler that may
174+
* need to be cancelled. As soon as this function is called, the
175+
* cancellation's 'cancel' callback may be called, at which point
176+
* the caller should proceed to call debugfs_leave_cancellation()
177+
* and leave the debugfs handler function as soon as possible.
178+
* Note that the 'cancel' callback is only ever called in the
179+
* context of some kind of debugfs_remove().
180+
*
181+
* This function must be paired with debugfs_leave_cancellation().
182+
*/
183+
void debugfs_enter_cancellation(struct file *file,
184+
struct debugfs_cancellation *cancellation)
185+
{
186+
struct debugfs_fsdata *fsd;
187+
struct dentry *dentry = F_DENTRY(file);
188+
189+
INIT_LIST_HEAD(&cancellation->list);
190+
191+
if (WARN_ON(!d_is_reg(dentry)))
192+
return;
193+
194+
if (WARN_ON(!cancellation->cancel))
195+
return;
196+
197+
fsd = READ_ONCE(dentry->d_fsdata);
198+
if (WARN_ON(!fsd ||
199+
((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)))
200+
return;
201+
202+
mutex_lock(&fsd->cancellations_mtx);
203+
list_add(&cancellation->list, &fsd->cancellations);
204+
mutex_unlock(&fsd->cancellations_mtx);
205+
206+
/* if we're already removing wake it up to cancel */
207+
if (d_unlinked(dentry))
208+
complete(&fsd->active_users_drained);
209+
}
210+
EXPORT_SYMBOL_GPL(debugfs_enter_cancellation);
211+
212+
/**
213+
* debugfs_leave_cancellation - leave cancellation section
214+
* @file: the file being accessed
215+
* @cancellation: the cancellation previously registered with
216+
* debugfs_enter_cancellation()
217+
*
218+
* See the documentation of debugfs_enter_cancellation().
219+
*/
220+
void debugfs_leave_cancellation(struct file *file,
221+
struct debugfs_cancellation *cancellation)
222+
{
223+
struct debugfs_fsdata *fsd;
224+
struct dentry *dentry = F_DENTRY(file);
225+
226+
if (WARN_ON(!d_is_reg(dentry)))
227+
return;
228+
229+
fsd = READ_ONCE(dentry->d_fsdata);
230+
if (WARN_ON(!fsd ||
231+
((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)))
232+
return;
233+
234+
mutex_lock(&fsd->cancellations_mtx);
235+
if (!list_empty(&cancellation->list))
236+
list_del(&cancellation->list);
237+
mutex_unlock(&fsd->cancellations_mtx);
238+
}
239+
EXPORT_SYMBOL_GPL(debugfs_leave_cancellation);
240+
141241
/*
142242
* Only permit access to world-readable files when the kernel is locked down.
143243
* We also need to exclude any file that has ways to write or alter it as root

fs/debugfs/inode.c

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -236,17 +236,29 @@ static const struct super_operations debugfs_super_operations = {
236236

237237
static void debugfs_release_dentry(struct dentry *dentry)
238238
{
239-
void *fsd = dentry->d_fsdata;
239+
struct debugfs_fsdata *fsd = dentry->d_fsdata;
240240

241-
if (!((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT))
242-
kfree(dentry->d_fsdata);
241+
if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)
242+
return;
243+
244+
/* check it wasn't a dir (no fsdata) or automount (no real_fops) */
245+
if (fsd && fsd->real_fops) {
246+
#ifdef CONFIG_LOCKDEP
247+
lockdep_unregister_key(&fsd->key);
248+
kfree(fsd->lock_name);
249+
#endif
250+
WARN_ON(!list_empty(&fsd->cancellations));
251+
mutex_destroy(&fsd->cancellations_mtx);
252+
}
253+
254+
kfree(fsd);
243255
}
244256

245257
static struct vfsmount *debugfs_automount(struct path *path)
246258
{
247-
debugfs_automount_t f;
248-
f = (debugfs_automount_t)path->dentry->d_fsdata;
249-
return f(path->dentry, d_inode(path->dentry)->i_private);
259+
struct debugfs_fsdata *fsd = path->dentry->d_fsdata;
260+
261+
return fsd->automount(path->dentry, d_inode(path->dentry)->i_private);
250262
}
251263

252264
static const struct dentry_operations debugfs_dops = {
@@ -634,27 +646,38 @@ struct dentry *debugfs_create_automount(const char *name,
634646
void *data)
635647
{
636648
struct dentry *dentry = start_creating(name, parent);
649+
struct debugfs_fsdata *fsd;
637650
struct inode *inode;
638651

639652
if (IS_ERR(dentry))
640653
return dentry;
641654

655+
fsd = kzalloc(sizeof(*fsd), GFP_KERNEL);
656+
if (!fsd) {
657+
failed_creating(dentry);
658+
return ERR_PTR(-ENOMEM);
659+
}
660+
661+
fsd->automount = f;
662+
642663
if (!(debugfs_allow & DEBUGFS_ALLOW_API)) {
643664
failed_creating(dentry);
665+
kfree(fsd);
644666
return ERR_PTR(-EPERM);
645667
}
646668

647669
inode = debugfs_get_inode(dentry->d_sb);
648670
if (unlikely(!inode)) {
649671
pr_err("out of free dentries, can not create automount '%s'\n",
650672
name);
673+
kfree(fsd);
651674
return failed_creating(dentry);
652675
}
653676

654677
make_empty_dir_inode(inode);
655678
inode->i_flags |= S_AUTOMOUNT;
656679
inode->i_private = data;
657-
dentry->d_fsdata = (void *)f;
680+
dentry->d_fsdata = fsd;
658681
/* directory inodes start off with i_nlink == 2 (for "." entry) */
659682
inc_nlink(inode);
660683
d_instantiate(dentry, inode);
@@ -731,8 +754,40 @@ static void __debugfs_file_removed(struct dentry *dentry)
731754
fsd = READ_ONCE(dentry->d_fsdata);
732755
if ((unsigned long)fsd & DEBUGFS_FSDATA_IS_REAL_FOPS_BIT)
733756
return;
734-
if (!refcount_dec_and_test(&fsd->active_users))
757+
758+
lock_map_acquire(&fsd->lockdep_map);
759+
lock_map_release(&fsd->lockdep_map);
760+
761+
/* if we hit zero, just wait for all to finish */
762+
if (!refcount_dec_and_test(&fsd->active_users)) {
763+
wait_for_completion(&fsd->active_users_drained);
764+
return;
765+
}
766+
767+
/* if we didn't hit zero, try to cancel any we can */
768+
while (refcount_read(&fsd->active_users)) {
769+
struct debugfs_cancellation *c;
770+
771+
/*
772+
* Lock the cancellations. Note that the cancellations
773+
* structs are meant to be on the stack, so we need to
774+
* ensure we either use them here or don't touch them,
775+
* and debugfs_leave_cancellation() will wait for this
776+
* to be finished processing before exiting one. It may
777+
* of course win and remove the cancellation, but then
778+
* chances are we never even got into this bit, we only
779+
* do if the refcount isn't zero already.
780+
*/
781+
mutex_lock(&fsd->cancellations_mtx);
782+
while ((c = list_first_entry_or_null(&fsd->cancellations,
783+
typeof(*c), list))) {
784+
list_del_init(&c->list);
785+
c->cancel(dentry, c->cancel_data);
786+
}
787+
mutex_unlock(&fsd->cancellations_mtx);
788+
735789
wait_for_completion(&fsd->active_users_drained);
790+
}
736791
}
737792

738793
static void remove_one(struct dentry *victim)

fs/debugfs/internal.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#ifndef _DEBUGFS_INTERNAL_H_
99
#define _DEBUGFS_INTERNAL_H_
10+
#include <linux/lockdep.h>
11+
#include <linux/list.h>
1012

1113
struct file_operations;
1214

@@ -17,8 +19,23 @@ extern const struct file_operations debugfs_full_proxy_file_operations;
1719

1820
struct debugfs_fsdata {
1921
const struct file_operations *real_fops;
20-
refcount_t active_users;
21-
struct completion active_users_drained;
22+
union {
23+
/* automount_fn is used when real_fops is NULL */
24+
debugfs_automount_t automount;
25+
struct {
26+
refcount_t active_users;
27+
struct completion active_users_drained;
28+
#ifdef CONFIG_LOCKDEP
29+
struct lockdep_map lockdep_map;
30+
struct lock_class_key key;
31+
char *lock_name;
32+
#endif
33+
34+
/* protect cancellations */
35+
struct mutex cancellations_mtx;
36+
struct list_head cancellations;
37+
};
38+
};
2239
};
2340

2441
/*

include/linux/debugfs.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,25 @@ ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf,
171171
ssize_t debugfs_read_file_str(struct file *file, char __user *user_buf,
172172
size_t count, loff_t *ppos);
173173

174+
/**
175+
* struct debugfs_cancellation - cancellation data
176+
* @list: internal, for keeping track
177+
* @cancel: callback to call
178+
* @cancel_data: extra data for the callback to call
179+
*/
180+
struct debugfs_cancellation {
181+
struct list_head list;
182+
void (*cancel)(struct dentry *, void *);
183+
void *cancel_data;
184+
};
185+
186+
void __acquires(cancellation)
187+
debugfs_enter_cancellation(struct file *file,
188+
struct debugfs_cancellation *cancellation);
189+
void __releases(cancellation)
190+
debugfs_leave_cancellation(struct file *file,
191+
struct debugfs_cancellation *cancellation);
192+
174193
#else
175194

176195
#include <linux/err.h>

include/linux/ieee80211.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2830,12 +2830,14 @@ ieee80211_he_oper_size(const u8 *he_oper_ie)
28302830
static inline const struct ieee80211_he_6ghz_oper *
28312831
ieee80211_he_6ghz_oper(const struct ieee80211_he_operation *he_oper)
28322832
{
2833-
const u8 *ret = (const void *)&he_oper->optional;
2833+
const u8 *ret;
28342834
u32 he_oper_params;
28352835

28362836
if (!he_oper)
28372837
return NULL;
28382838

2839+
ret = (const void *)&he_oper->optional;
2840+
28392841
he_oper_params = le32_to_cpu(he_oper->he_oper_params);
28402842

28412843
if (!(he_oper_params & IEEE80211_HE_OPERATION_6GHZ_OP_INFO))

0 commit comments

Comments
 (0)