summaryrefslogtreecommitdiff
path: root/exec.c
diff options
context:
space:
mode:
authorStefan Hajnoczi <stefanha@redhat.com>2014-12-02 11:23:18 +0000
committerPaolo Bonzini <pbonzini@redhat.com>2015-06-05 17:10:00 +0200
commit03eebc9e3246b9b3f5925aa41f7dfd7c1e467875 (patch)
tree74641e34056f1169770c48aa604477315210d6be /exec.c
parent20015f72bda7d2f356c43580a5542a659afedf83 (diff)
downloadqemu-03eebc9e3246b9b3f5925aa41f7dfd7c1e467875.tar.gz
memory: replace cpu_physical_memory_reset_dirty() with test-and-clear
The cpu_physical_memory_reset_dirty() function is sometimes used together with cpu_physical_memory_get_dirty(). This is not atomic since two separate accesses to the dirty memory bitmap are made. Turn cpu_physical_memory_reset_dirty() and cpu_physical_memory_clear_dirty_range_type() into the atomic cpu_physical_memory_test_and_clear_dirty(). Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com> Message-Id: <1417519399-3166-6-git-send-email-stefanha@redhat.com> Reviewed-by: Fam Zheng <famz@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'exec.c')
-rw-r--r--exec.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/exec.c b/exec.c
index 162c57908e..487583b1bd 100644
--- a/exec.c
+++ b/exec.c
@@ -852,16 +852,27 @@ static void tlb_reset_dirty_range_all(ram_addr_t start, ram_addr_t length)
}
/* Note: start and end must be within the same ram block. */
-void cpu_physical_memory_reset_dirty(ram_addr_t start, ram_addr_t length,
- unsigned client)
+bool cpu_physical_memory_test_and_clear_dirty(ram_addr_t start,
+ ram_addr_t length,
+ unsigned client)
{
- if (length == 0)
- return;
- cpu_physical_memory_clear_dirty_range_type(start, length, client);
+ unsigned long end, page;
+ bool dirty;
- if (tcg_enabled()) {
+ if (length == 0) {
+ return false;
+ }
+
+ end = TARGET_PAGE_ALIGN(start + length) >> TARGET_PAGE_BITS;
+ page = start >> TARGET_PAGE_BITS;
+ dirty = bitmap_test_and_clear_atomic(ram_list.dirty_memory[client],
+ page, end - page);
+
+ if (dirty && tcg_enabled()) {
tlb_reset_dirty_range_all(start, length);
}
+
+ return dirty;
}
/* Called from RCU critical section */