dm: safely access MMIO hint in MMIO emulation

mmio_hint in mem.c can potentially be accessed concurrently in
emulate_mem() because it only holds a read lock. Use a local variable to
make sure the same entry address is used throughout the function. Since
it only serves as a hint, it's okay if the function does not use the
most up-to-date version of mmio_hint, as long as mmio_hint is accessed
atomically.

Explicitly enforce natural alignment on mmio_hint to guarantee atomic
accesses on x86 and increase code portability, even though compilers
most likely always do it.

Entries in the RB tree are only removed in unregister_mem_int() while
holding a write lock, so accessing mmio_hint while holding a read lock
is safe.

Tracked-On: #2902
Signed-off-by: Peter Fang <peter.fang@intel.com>
Reviewed-by: Shuo A Liu <shuo.a.liu@intel.com>
This commit is contained in:
Peter Fang 2019-04-16 22:12:41 -07:00 committed by ACRN System Integration
parent 4c38ff00c6
commit 82fa9946e0

View File

@ -60,7 +60,7 @@ RB_PROTOTYPE_STATIC(mmio_rb_tree, mmio_rb_range, mr_link, mmio_rb_range_compare)
* consecutive addresses in a range, it makes sense to cache the
* result of a lookup.
*/
static struct mmio_rb_range *mmio_hint;
static struct mmio_rb_range *mmio_hint __aligned(sizeof(struct mmio_rb_range *));
static pthread_rwlock_t mmio_rwlock;
@ -156,16 +156,18 @@ emulate_mem(struct vmctx *ctx, struct mmio_request *mmio_req)
{
uint64_t paddr = mmio_req->address;
int size = mmio_req->size;
struct mmio_rb_range *entry = NULL;
struct mmio_rb_range *hint, *entry = NULL;
int err;
pthread_rwlock_rdlock(&mmio_rwlock);
/*
* First check the per-VM cache
*/
if (mmio_hint && paddr >= mmio_hint->mr_base &&
paddr <= mmio_hint->mr_end)
entry = mmio_hint;
hint = mmio_hint;
if (hint && paddr >= hint->mr_base && paddr <= hint->mr_end)
entry = hint;
else if (mmio_rb_lookup(&mmio_rb_root, paddr, &entry) == 0)
/* Update the per-VM cache */
mmio_hint = entry;