From 9479199c6b72cb294e0d965f8e6b9055bec718bf Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 22 Feb 2018 19:51:24 -0500 Subject: [PATCH] memory: fix usage of find_next_bit and find_next_zero_bit The last two arguments to these functions are the last and first bit to check relative to the base. The code was using incorrectly the first bit and the number of bits. Fix this in cpu_physical_memory_get_dirty and cpu_physical_memory_all_dirty. This requires a few changes in the iteration; change the code in cpu_physical_memory_set_dirty_range to match. Backports commit 88c73d16ad1b6c22a2ab082064d0d521f756296a from qemu --- qemu/include/exec/ram_addr.h | 51 ++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/qemu/include/exec/ram_addr.h b/qemu/include/exec/ram_addr.h index 96a01042..cae0fa7f 100644 --- a/qemu/include/exec/ram_addr.h +++ b/qemu/include/exec/ram_addr.h @@ -76,6 +76,7 @@ static inline bool cpu_physical_memory_get_dirty(struct uc_struct *uc, ram_addr_ { DirtyMemoryBlocks *blocks; unsigned long end, page; + unsigned long idx, offset, base; bool dirty = false; assert(client < DIRTY_MEMORY_NUM); @@ -89,17 +90,22 @@ static inline bool cpu_physical_memory_get_dirty(struct uc_struct *uc, ram_addr_ // Unicorn: atomic_read used instead of atomic_rcu_read blocks = atomic_read(&uc->ram_list.dirty_memory[client]); + idx = page / DIRTY_MEMORY_BLOCK_SIZE; + offset = page % DIRTY_MEMORY_BLOCK_SIZE; + base = page - offset; while (page < end) { - unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE; - unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE; - unsigned long num = MIN(end - page, DIRTY_MEMORY_BLOCK_SIZE - offset); - - if (find_next_bit(blocks->blocks[idx], offset, num) < num) { + unsigned long next = MIN(end, base + DIRTY_MEMORY_BLOCK_SIZE); + unsigned long num = next - base; + unsigned long found = find_next_bit(blocks->blocks[idx], num, offset); + if (found < num) { dirty = true; break; } - page += num; + page = next; + idx++; + offset = 0; + base += DIRTY_MEMORY_BLOCK_SIZE; } // Unicorn: commented out @@ -115,6 +121,7 @@ static inline bool cpu_physical_memory_all_dirty(struct uc_struct *uc, ram_addr_ { DirtyMemoryBlocks *blocks; unsigned long end, page; + unsigned long idx, offset, base; bool dirty = true; assert(client < DIRTY_MEMORY_NUM); @@ -128,17 +135,22 @@ static inline bool cpu_physical_memory_all_dirty(struct uc_struct *uc, ram_addr_ // Unicorn: atomic_read used instead of atomic_rcu_read blocks = atomic_read(&uc->ram_list.dirty_memory[client]); + idx = page / DIRTY_MEMORY_BLOCK_SIZE; + offset = page % DIRTY_MEMORY_BLOCK_SIZE; + base = page - offset; while (page < end) { - unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE; - unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE; - unsigned long num = MIN(end - page, DIRTY_MEMORY_BLOCK_SIZE - offset); - - if (find_next_zero_bit(blocks->blocks[idx], offset, num) < num) { + unsigned long next = MIN(end, base + DIRTY_MEMORY_BLOCK_SIZE); + unsigned long num = next - base; + unsigned long found = find_next_zero_bit(blocks->blocks[idx], num, offset); + if (found < num) { dirty = false; break; } - page += num; + page = next; + idx++; + offset = 0; + base += DIRTY_MEMORY_BLOCK_SIZE; } // Unicorn: commented out @@ -200,6 +212,7 @@ static inline void cpu_physical_memory_set_dirty_range(struct uc_struct *uc, ram { DirtyMemoryBlocks *blocks[DIRTY_MEMORY_NUM]; unsigned long end, page; + unsigned long idx, offset, base; int i; if (!mask && !xen_enabled()) { @@ -217,17 +230,21 @@ static inline void cpu_physical_memory_set_dirty_range(struct uc_struct *uc, ram blocks[i] = atomic_read(&uc->ram_list.dirty_memory[i]); } + idx = page / DIRTY_MEMORY_BLOCK_SIZE; + offset = page % DIRTY_MEMORY_BLOCK_SIZE; + base = page - offset; while (page < end) { - unsigned long idx = page / DIRTY_MEMORY_BLOCK_SIZE; - unsigned long offset = page % DIRTY_MEMORY_BLOCK_SIZE; - unsigned long num = MIN(end - page, DIRTY_MEMORY_BLOCK_SIZE - offset); + unsigned long next = MIN(end, base + DIRTY_MEMORY_BLOCK_SIZE); if (unlikely(mask & (1 << DIRTY_MEMORY_CODE))) { bitmap_set_atomic(blocks[DIRTY_MEMORY_CODE]->blocks[idx], - offset, num); + offset, next - page); } - page += num; + page = next; + idx++; + offset = 0; + base += DIRTY_MEMORY_BLOCK_SIZE; } // Unicorn: commented out