Message ID | 20250221123536.2946377-1-lizhi.xu@windriver.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | [V2] module: replace the mutex lock acquisition method | expand |
On Fri, Feb 21, 2025 at 1:35 PM Lizhi Xu <lizhi.xu@windriver.com> wrote: > > syzbot reported a deadlock in lock_system_sleep. [1] > > The write operation to "/sys/module/hibernate/parameters/compressor" > conflicts with the registration of ieee80211 device, resulting in a deadlock > in the lock param_lock. > > Since the conflict cannot be avoided, the way to obtain param_lock is changed > to trylock to avoid deadlock. An alternative way to avoid the deadlock would be to replace lock_system_sleep() in hibernate_compressor_param_set() with mutex_trylock(&system_transition_mutex) (and analogously for the unlock operation). Why have you not done that? It is arguably better to fail a write to the module param with -EBUSY than to fail ieee80211_register_hw() IMV.
On Fri, 21 Feb 2025 21:07:59 +0100, Rafael J. Wysocki" <rafael@kernel.org> wrote: > > syzbot reported a deadlock in lock_system_sleep. [1] > > > > The write operation to "/sys/module/hibernate/parameters/compressor" > > conflicts with the registration of ieee80211 device, resulting in a deadlock > > in the lock param_lock. > > > > Since the conflict cannot be avoided, the way to obtain param_lock is changed > > to trylock to avoid deadlock. > > An alternative way to avoid the deadlock would be to replace > lock_system_sleep() in hibernate_compressor_param_set() with > mutex_trylock(&system_transition_mutex) (and analogously for the > unlock operation). Why have you not done that? Yes, you are right, I have confirmed that can work fine. I will send V2 patch for using mutex_trylock(&system_transition_mutex). BR, Lizhi
diff --git a/include/linux/moduleparam.h b/include/linux/moduleparam.h index bfb85fd13e1f..cbcbfd8db721 100644 --- a/include/linux/moduleparam.h +++ b/include/linux/moduleparam.h @@ -306,11 +306,15 @@ struct kparam_array #ifdef CONFIG_SYSFS extern void kernel_param_lock(struct module *mod); +extern int kernel_param_trylock(struct module *mod); extern void kernel_param_unlock(struct module *mod); #else static inline void kernel_param_lock(struct module *mod) { } +static inline int kernel_param_trylock(struct module *mod) +{ +} static inline void kernel_param_unlock(struct module *mod) { } diff --git a/kernel/params.c b/kernel/params.c index 0074d29c9b80..d19881fbb2ec 100644 --- a/kernel/params.c +++ b/kernel/params.c @@ -583,7 +583,9 @@ static ssize_t param_attr_store(const struct module_attribute *mattr, if (!attribute->param->ops->set) return -EPERM; - kernel_param_lock(mk->mod); + if (!kernel_param_trylock(mk->mod)) + return -EAGAIN; + if (param_check_unsafe(attribute->param)) err = attribute->param->ops->set(buf, attribute->param); else @@ -607,6 +609,11 @@ void kernel_param_lock(struct module *mod) mutex_lock(KPARAM_MUTEX(mod)); } +int kernel_param_trylock(struct module *mod) +{ + return mutex_trylock(KPARAM_MUTEX(mod)); +} + void kernel_param_unlock(struct module *mod) { mutex_unlock(KPARAM_MUTEX(mod)); diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 0d056db9f81e..aecf7ff51cd9 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -217,7 +217,9 @@ ieee80211_rate_control_ops_get(const char *name) const struct rate_control_ops *ops; const char *alg_name; - kernel_param_lock(THIS_MODULE); + if (!kernel_param_trylock(THIS_MODULE)) + return NULL; + if (!name) alg_name = ieee80211_default_rc_algo; else