From 5ed3dbf93c175e270094dead35904aeb753cb0bf Mon Sep 17 00:00:00 2001 From: Long Liu Date: Wed, 25 Apr 2018 10:49:53 +0800 Subject: [PATCH] Subject: DM: virtio-heci: Use atomic_xchange in client get/put With rare probability, the two threads may try to get&put client together. For client getting, the subsequent thread will get one destroyed client. For client putting, it will cause acrn-dm get crashed due to assert be triggered in virtio_heci_client_put. Signed-off-by: Long Liu Reviewed-by: Shuo Liu Reviewed-by: Yu Wang Acked-by: Eddie Dong --- devicemodel/hw/pci/virtio/virtio_heci.c | 33 ++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/devicemodel/hw/pci/virtio/virtio_heci.c b/devicemodel/hw/pci/virtio/virtio_heci.c index 3ed23e6a6..98211f276 100644 --- a/devicemodel/hw/pci/virtio/virtio_heci.c +++ b/devicemodel/hw/pci/virtio/virtio_heci.c @@ -211,8 +211,23 @@ err_to_native_heci_resno(int err) static struct virtio_heci_client * virtio_heci_client_get(struct virtio_heci_client *client) { - if (__sync_fetch_and_add(&client->ref, 1) == 0) - return NULL; + int new, val; + + /* + * The active_clients be protected by list_mutex + * so the client never be null + */ + do { + val = *(volatile int *)&client->ref; + if (val == 0) + return NULL; + + new = val + 1; + + /* check for overflow */ + assert(new > 0); + + } while (!__sync_bool_compare_and_swap(&client->ref, val, new)); return client; } @@ -220,8 +235,18 @@ static void virtio_heci_client_put(struct virtio_heci *vheci, struct virtio_heci_client *client) { - assert(client->ref > 0); - if (__sync_sub_and_fetch(&client->ref, 1) == 0) + int new, val; + + do { + val = *(volatile int *)&client->ref; + if (val == 0) + return; + + new = val - 1; + + } while (!__sync_bool_compare_and_swap(&client->ref, val, new)); + + if (client->ref == 0) virtio_heci_destroy_client(vheci, client); }