From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: "Zheng, Gen" Date: Fri, 31 Aug 2018 10:59:01 +0800 Subject: [PATCH] VHM: bug fix on operating multi-thread synchronization With current code, the ioreq client based on VHM kthread may access client->wq after the client got freed. The acrn_ioreq_destroy_client_pervm should wait for the client thread exit then free its client. So do the following fixes: Make the client threads for vcpu and hyper-dma mark kthread_exit flag as true before exit. Make the task that triggered to destroy the client thread, explicitly waits for the kthread_exit flag turnning to true. Signed-off-by: Zheng, Gen Reviewed-by: Chen, Jason CJ Reviewed-by: Zhao, Yakui --- drivers/vhm/vhm_ioreq.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/drivers/vhm/vhm_ioreq.c b/drivers/vhm/vhm_ioreq.c index 08826c575780..b570b826be95 100644 --- a/drivers/vhm/vhm_ioreq.c +++ b/drivers/vhm/vhm_ioreq.c @@ -91,8 +91,8 @@ struct ioreq_client { */ bool fallback; - bool destroying; - bool kthread_exit; + volatile bool destroying; + volatile bool kthread_exit; /* client covered io ranges - N/A for fallback client */ struct list_head range_list; @@ -260,15 +260,15 @@ static void acrn_ioreq_destroy_client_pervm(struct ioreq_client *client, struct list_head *pos, *tmp; unsigned long flags; - /* blocking operation: notify client for cleanup - * if waitqueue not active, it means client is handling request, - * at that time, we need wait client finish its handling. - */ - while (!waitqueue_active(&client->wq) && !client->kthread_exit) - msleep(10); client->destroying = true; acrn_ioreq_notify_client(client); + /* the client thread will mark kthread_exit flag as true before exit, + * so wait for it exited. + */ + while (!client->kthread_exit) + msleep(10); + spin_lock_irqsave(&client->range_lock, flags); list_for_each_safe(pos, tmp, &client->range_list) { struct ioreq_range *range = @@ -495,6 +495,10 @@ static int ioreq_client_thread(void *data) is_destroying(client))); } + /* the client thread such as for hyper-dma will exit from here, + * so mark kthread_exit as true before exit */ + client->kthread_exit = true; + return 0; } @@ -543,8 +547,12 @@ int acrn_ioreq_attach_client(int client_id, bool check_kthread_stop) is_destroying(client))); } - if (is_destroying(client)) + if (is_destroying(client)) { + /* the client thread for vcpu will exit from here, + * so mark kthread_exit as true before exit */ + client->kthread_exit = true; return 1; + } } return 0; -- https://clearlinux.org