On Tue, 07 Nov 2023 09:17:59 +0100, 강신형 wrote: > > Task1 waits for mutex_lock, and task2 waits for pde to be unused.(deadlock) > /*call trace*/ > task1 Call trace: > __switch_to+0x174/0x338 > schedule+0x7c/0xe8 > schedule_preempt_disabled+0x24/0x40 > mutex_lock+0x40/0xec > snd_info_text_entry_open+0x28/0x120 > proc_reg_open+0xe4/0x248 > do_dentry_open+0x2a4/0x4e0 > > task2 Call trace: > schedule_timeout+0x44/0x1c8 > wait_for_completion+0x18/0x24 > proc_entry_rundown+0x60/0xf0 > remove_proc_subtree+0x180/0x218 > proc_remove+0x20/0x30 > snd_info_disconnect+0x4c/0x68 > snd_info_card_disconnect+0x3c/0x58 > snd_card_disconnect+0x130/0x264 > usb_audio_disconnect+0xc0/0x24c > > /*the sequence*/ > task1: > - proc_reg_open: set the use_pde > task2: > - usb_audio_disconnect: usb device disconnection occurs > - snd_info_card_disconnect: acquire the mutex_lock(&info_mutex) > - proc_entry_rundown: wait_for_completion(unuse_pde) > task1: > - wait for mutex_lock in snd_info_text_entry_open > > To avoid it, a mutex without wating(mutex_trylock) shoud be used in > snd_info_text_entry_open(task1). > Then, when mutex_lock acquisition fails, an error is returned, and the pde > becomes unused, and the mutex_lock held by task2 is released. > > > Signed-off-by: Shinhyung Kang <s47.kang@xxxxxxxxxxx> Thanks for the patch. But this change may break the current working behavior; e.g. when two proc reads are running concurrently, one would be aborted unexpectedly. IIUC, the problem is the call of proc_remove(), and this call itself can be outside the global mutex. Could you check whether the patch below works instead? (Note that it's only compile-tested.) It makes the proc_remove() called at first, then clearing the internal entries. The function was renamed accordingly for avoiding confusion, too. Takashi --- a/sound/core/info.c +++ b/sound/core/info.c @@ -56,7 +56,7 @@ struct snd_info_private_data { }; static int snd_info_version_init(void); -static void snd_info_disconnect(struct snd_info_entry *entry); +static void snd_info_clear_entries(struct snd_info_entry *entry); /* @@ -569,11 +569,16 @@ void snd_info_card_disconnect(struct snd_card *card) { if (!card) return; - mutex_lock(&info_mutex); + proc_remove(card->proc_root_link); - card->proc_root_link = NULL; if (card->proc_root) - snd_info_disconnect(card->proc_root); + proc_remove(card->proc_root->p); + + mutex_lock(&info_mutex); + if (card->proc_root) + snd_info_clear_entries(card->proc_root); + card->proc_root_link = NULL; + card->proc_root = NULL; mutex_unlock(&info_mutex); } @@ -745,15 +750,14 @@ struct snd_info_entry *snd_info_create_card_entry(struct snd_card *card, } EXPORT_SYMBOL(snd_info_create_card_entry); -static void snd_info_disconnect(struct snd_info_entry *entry) +static void snd_info_clear_entries(struct snd_info_entry *entry) { struct snd_info_entry *p; if (!entry->p) return; list_for_each_entry(p, &entry->children, list) - snd_info_disconnect(p); - proc_remove(entry->p); + snd_info_clear_entries(p); entry->p = NULL; } @@ -770,8 +774,9 @@ void snd_info_free_entry(struct snd_info_entry * entry) if (!entry) return; if (entry->p) { + proc_remove(entry->p); mutex_lock(&info_mutex); - snd_info_disconnect(entry); + snd_info_clear_entries(entry); mutex_unlock(&info_mutex); }