From 82fa9946e0cd86eb9a1a2d4c91e93e45d601890c Mon Sep 17 00:00:00 2001 From: Peter Fang Date: Tue, 16 Apr 2019 22:12:41 -0700 Subject: [PATCH] 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 Reviewed-by: Shuo A Liu --- devicemodel/core/mem.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/devicemodel/core/mem.c b/devicemodel/core/mem.c index 7a30f26bb..59242b200 100644 --- a/devicemodel/core/mem.c +++ b/devicemodel/core/mem.c @@ -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;