Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: bnep: Fix deadlock in session deletion

Commit f4d7cd4a4c introduced the usage of kthread API.
kthread_stop is a blocking function which returns only when
the thread exits. In this case, the thread can't exit because it's
waiting for the write lock, which is being held by bnep_del_connection()
which is waiting for the thread to exit -- deadlock.

Use atomic_t/wake_up_process instead to signal to the thread to exit.

Signed-off-by: Jaikumar Ganesh <jaikumar@google.com>
Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>

authored by

Peter Hurley and committed by
Gustavo F. Padovan
751c10a5 7bdb8a5c

+6 -4
+1
net/bluetooth/bnep/bnep.h
··· 155 155 unsigned int role; 156 156 unsigned long state; 157 157 unsigned long flags; 158 + atomic_t terminate; 158 159 struct task_struct *task; 159 160 160 161 struct ethhdr eh;
+5 -4
net/bluetooth/bnep/core.c
··· 487 487 while (1) { 488 488 set_current_state(TASK_INTERRUPTIBLE); 489 489 490 - if (kthread_should_stop()) 490 + if (atomic_read(&s->terminate)) 491 491 break; 492 492 /* RX */ 493 493 while ((skb = skb_dequeue(&sk->sk_receive_queue))) { ··· 642 642 down_read(&bnep_session_sem); 643 643 644 644 s = __bnep_get_session(req->dst); 645 - if (s) 646 - kthread_stop(s->task); 647 - else 645 + if (s) { 646 + atomic_inc(&s->terminate); 647 + wake_up_process(s->task); 648 + } else 648 649 err = -ENOENT; 649 650 650 651 up_read(&bnep_session_sem);