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 <shuo.a.liu@intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Acked-by: Yin Fengwei <fengwei.yin@intel.com>
This commit is contained in:
parent
b1047224aa
commit
580579a392
|
@ -140,16 +140,43 @@ struct refcnt {
|
||||||
int count;
|
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)
|
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
|
static inline void
|
||||||
refcnt_put(const struct refcnt *ref)
|
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);
|
ref->destroy(ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -803,7 +830,6 @@ static int vmei_me_client_scan_list(struct virtio_mei *vmei)
|
||||||
|
|
||||||
if (ent->d_type == DT_DIR &&
|
if (ent->d_type == DT_DIR &&
|
||||||
is_prefix("mei::", ent->d_name, DEV_NAME_SIZE)) {
|
is_prefix("mei::", ent->d_name, DEV_NAME_SIZE)) {
|
||||||
|
|
||||||
struct mei_client_properties props;
|
struct mei_client_properties props;
|
||||||
|
|
||||||
memset(&props, 0, sizeof(props));
|
memset(&props, 0, sizeof(props));
|
||||||
|
|
Loading…
Reference in New Issue