From 580579a39255a2587be42cd83d31a70eb3cfae49 Mon Sep 17 00:00:00 2001 From: Tomas Winkler Date: Thu, 22 Nov 2018 10:14:47 +0200 Subject: [PATCH] dm: mei: Use compare and swap primitive for refcnt. Simple atomic add/dec do no guarantee reference count full synchronization without a lock. Compare and swap operations are required for correct implementation. Tracked-On: #1875 Signed-off-by: Shuo A Liu Signed-off-by: Tomas Winkler Acked-by: Yin Fengwei --- devicemodel/hw/pci/virtio/virtio_mei.c | 34 +++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/devicemodel/hw/pci/virtio/virtio_mei.c b/devicemodel/hw/pci/virtio/virtio_mei.c index 1231b226f..f50c587a1 100644 --- a/devicemodel/hw/pci/virtio/virtio_mei.c +++ b/devicemodel/hw/pci/virtio/virtio_mei.c @@ -140,16 +140,43 @@ struct refcnt { int count; }; -static inline void +static inline int atomic_read(const struct refcnt *ref) +{ + return *(volatile int *)&ref->count; +} + +static inline int refcnt_get(const struct refcnt *ref) { - __sync_add_and_fetch((int *)&ref->count, 1); + int new, val; + + do { + val = atomic_read(ref); + if (val == 0) + return 0; + + new = val + 1; + /* check for overflow */ + assert(new > 0); + + } while (!__sync_bool_compare_and_swap((int *)&ref->count, val, new)); + + return new; } static inline void refcnt_put(const struct refcnt *ref) { - if (__sync_sub_and_fetch((int *)&ref->count, 1) == 0) + int new, val; + + do { + val = atomic_read(ref); + if (val == 0) + return; + new = val - 1; + } while (!__sync_bool_compare_and_swap((int *)&ref->count, val, new)); + + if (new == 0) ref->destroy(ref); } @@ -803,7 +830,6 @@ static int vmei_me_client_scan_list(struct virtio_mei *vmei) if (ent->d_type == DT_DIR && is_prefix("mei::", ent->d_name, DEV_NAME_SIZE)) { - struct mei_client_properties props; memset(&props, 0, sizeof(props));