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

Bluetooth: cmtp: fix possible might sleep error in cmtp_session

It looks like cmtp_session has same pattern as the issue reported in
old rfcomm:

while (1) {
set_current_state(TASK_INTERRUPTIBLE);
if (condition)
break;
// may call might_sleep here
schedule();
}
__set_current_state(TASK_RUNNING);

Which fixed at:
dfb2fae Bluetooth: Fix nested sleeps

So let's fix it at the same way, also follow the suggestion of:
https://lwn.net/Articles/628628/

Signed-off-by: Jeffy Chen <jeffy.chen@rock-chips.com>
Reviewed-by: Brian Norris <briannorris@chromium.org>
Reviewed-by: AL Yu-Chen Cho <acho@suse.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

authored by

Jeffy Chen and committed by
Marcel Holtmann
f06d9773 25717382

+10 -7
+10 -7
net/bluetooth/cmtp/core.c
··· 280 280 struct cmtp_session *session = arg; 281 281 struct sock *sk = session->sock->sk; 282 282 struct sk_buff *skb; 283 - wait_queue_t wait; 283 + DEFINE_WAIT_FUNC(wait, woken_wake_function); 284 284 285 285 BT_DBG("session %p", session); 286 286 287 287 set_user_nice(current, -15); 288 288 289 - init_waitqueue_entry(&wait, current); 290 289 add_wait_queue(sk_sleep(sk), &wait); 291 290 while (1) { 292 - set_current_state(TASK_INTERRUPTIBLE); 291 + /* Ensure session->terminate is updated */ 292 + smp_mb__before_atomic(); 293 293 294 294 if (atomic_read(&session->terminate)) 295 295 break; ··· 306 306 307 307 cmtp_process_transmit(session); 308 308 309 - schedule(); 309 + wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); 310 310 } 311 - __set_current_state(TASK_RUNNING); 312 311 remove_wait_queue(sk_sleep(sk), &wait); 313 312 314 313 down_write(&cmtp_session_sem); ··· 392 393 err = cmtp_attach_device(session); 393 394 if (err < 0) { 394 395 atomic_inc(&session->terminate); 395 - wake_up_process(session->task); 396 + wake_up_interruptible(sk_sleep(session->sock->sk)); 396 397 up_write(&cmtp_session_sem); 397 398 return err; 398 399 } ··· 430 431 431 432 /* Stop session thread */ 432 433 atomic_inc(&session->terminate); 433 - wake_up_process(session->task); 434 + 435 + /* Ensure session->terminate is updated */ 436 + smp_mb__after_atomic(); 437 + 438 + wake_up_interruptible(sk_sleep(session->sock->sk)); 434 439 } else 435 440 err = -ENOENT; 436 441