Skip to content

Commit 4b13cbe

Browse files
mikechristiemstsirkin
authored andcommitted
vhost: Fix worker hangs due to missed wake up calls
We can race where we have added work to the work_list, but vhost_task_fn has passed that check but not yet set us into TASK_INTERRUPTIBLE. wake_up_process will see us in TASK_RUNNING and just return. This bug was intoduced in commit f9010db ("fork, vhost: Use CLONE_THREAD to fix freezer/ps regression") when I moved the setting of TASK_INTERRUPTIBLE to simplfy the code and avoid get_signal from logging warnings about being in the wrong state. This moves the setting of TASK_INTERRUPTIBLE back to before we test if we need to stop the task to avoid a possible race there as well. We then have vhost_worker set TASK_RUNNING if it finds work similar to before. Fixes: f9010db ("fork, vhost: Use CLONE_THREAD to fix freezer/ps regression") Signed-off-by: Mike Christie <[email protected]> Message-Id: <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]>
1 parent a284f09 commit 4b13cbe

File tree

2 files changed

+11
-7
lines changed

2 files changed

+11
-7
lines changed

drivers/vhost/vhost.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,8 @@ static bool vhost_worker(void *data)
341341

342342
node = llist_del_all(&worker->work_list);
343343
if (node) {
344+
__set_current_state(TASK_RUNNING);
345+
344346
node = llist_reverse_order(node);
345347
/* make sure flag is seen after deletion */
346348
smp_wmb();

kernel/vhost_task.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,6 @@ static int vhost_task_fn(void *data)
2828
for (;;) {
2929
bool did_work;
3030

31-
/* mb paired w/ vhost_task_stop */
32-
if (test_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags))
33-
break;
34-
3531
if (!dead && signal_pending(current)) {
3632
struct ksignal ksig;
3733
/*
@@ -48,11 +44,17 @@ static int vhost_task_fn(void *data)
4844
clear_thread_flag(TIF_SIGPENDING);
4945
}
5046

47+
/* mb paired w/ vhost_task_stop */
48+
set_current_state(TASK_INTERRUPTIBLE);
49+
50+
if (test_bit(VHOST_TASK_FLAGS_STOP, &vtsk->flags)) {
51+
__set_current_state(TASK_RUNNING);
52+
break;
53+
}
54+
5155
did_work = vtsk->fn(vtsk->data);
52-
if (!did_work) {
53-
set_current_state(TASK_INTERRUPTIBLE);
56+
if (!did_work)
5457
schedule();
55-
}
5658
}
5759

5860
complete(&vtsk->exited);

0 commit comments

Comments
 (0)