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 <long.liu@intel.com>
Reviewed-by: Shuo Liu <shuo.a.liu@intel.com>
Reviewed-by: Yu Wang <yu1.wang@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
This commit is contained in:
Long Liu 2018-04-25 10:49:53 +08:00 committed by Jack Ren
parent df2d925a27
commit 5ed3dbf93c

View File

@ -211,8 +211,23 @@ err_to_native_heci_resno(int err)
static struct virtio_heci_client * static struct virtio_heci_client *
virtio_heci_client_get(struct virtio_heci_client *client) virtio_heci_client_get(struct virtio_heci_client *client)
{ {
if (__sync_fetch_and_add(&client->ref, 1) == 0) int new, val;
return NULL;
/*
* 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; return client;
} }
@ -220,8 +235,18 @@ static void
virtio_heci_client_put(struct virtio_heci *vheci, virtio_heci_client_put(struct virtio_heci *vheci,
struct virtio_heci_client *client) struct virtio_heci_client *client)
{ {
assert(client->ref > 0); int new, val;
if (__sync_sub_and_fetch(&client->ref, 1) == 0)
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); virtio_heci_destroy_client(vheci, client);
} }