diff mbox

memory: fix usage of find_next_bit and find_next_zero_bit

Message ID 1455113505-11237-1-git-send-email-pbonzini@redhat.com
State New
Headers show

Commit Message

Paolo Bonzini Feb. 10, 2016, 2:11 p.m. UTC
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.

Fixes: 5b82b70
Cc: Stefan Hajnoczi <stefanha@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 include/exec/ram_addr.h | 55 ++++++++++++++++++++++++++++++++-----------------
 1 file changed, 36 insertions(+), 19 deletions(-)

Comments

Stefan Hajnoczi Feb. 10, 2016, 2:23 p.m. UTC | #1
On Wed, Feb 10, 2016 at 03:11:45PM +0100, Paolo Bonzini wrote:
> 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.
> 
> Fixes: 5b82b70
> Cc: Stefan Hajnoczi <stefanha@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  include/exec/ram_addr.h | 55 ++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 36 insertions(+), 19 deletions(-)

Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Leon Alrae Feb. 10, 2016, 5:29 p.m. UTC | #2
On 10/02/16 14:11, Paolo Bonzini wrote:
> 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.
> 
> Fixes: 5b82b70
> Cc: Stefan Hajnoczi <stefanha@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> ---
>  include/exec/ram_addr.h | 55 ++++++++++++++++++++++++++++++++-----------------
>  1 file changed, 36 insertions(+), 19 deletions(-)

It fixes the performance problem I was seeing:

Tested-by: Leon Alrae <leon.alrae@imgtec.com>

Thanks,
Leon
Thomas Huth Feb. 10, 2016, 5:44 p.m. UTC | #3
On 10.02.2016 15:11, Paolo Bonzini wrote:
> 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.
> 
> Fixes: 5b82b70
> Cc: Stefan Hajnoczi <stefanha@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

That commit 5b82b70 also broke the pseries machine on qemu-ppc64:

--------------------------------- 8< --------------------------------------
$ ppc64-softmmu/qemu-system-ppc64 -net none -nographic -vga none 


SLOF **********************************************************************
QEMU Starting
 Build Date = Nov  5 2015 15:23:31
 FW Version = git-b4c93802a5b2c72f
 Press "s" to enter Open Firmware.



SLOF **********************************************************************
QEMU Starting
 Build Date = Nov  5 2015 15:23:31
 FW Version = git-b4c93802a5b2c72f
ERROR: Flatten device tree not available!
 Press "s" to enter Open Firmware.

  !!! roomfs lookup(bootinfo) = 1
Cannot find romfs file xvect
  !!! roomfs lookup(bootinfo) = 1
ERROR: Not enough memory for Open Firmware
qemu: fatal: Trying to execute code outside RAM or ROM at 0xffffffffffbf0000
--------------------------------- 8< --------------------------------------

With your patch here applied, SLOF boots fine again, so:

Tested-by: Thomas Huth <thuth@redhat.com>
Peter Maydell Feb. 10, 2016, 10:40 p.m. UTC | #4
On 10 February 2016 at 14:11, Paolo Bonzini <pbonzini@redhat.com> wrote:
> 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.
>
> Fixes: 5b82b70
> Cc: Stefan Hajnoczi <stefanha@redhat.com>
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

I've set the pre-merge tests running so I should be able
to commit this to master first thing tomorrow. Was this
the only patch that needs applying to fix your pullreq?

thanks
-- PMM
Paolo Bonzini Feb. 11, 2016, 9:46 a.m. UTC | #5
On 10/02/2016 23:40, Peter Maydell wrote:
> On 10 February 2016 at 14:11, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> 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.
>>
>> Fixes: 5b82b70
>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
> 
> I've set the pre-merge tests running so I should be able
> to commit this to master first thing tomorrow. Was this
> the only patch that needs applying to fix your pullreq?

Nothing else.

Paolo
Peter Maydell Feb. 11, 2016, 10:34 a.m. UTC | #6
On 10 February 2016 at 22:40, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 10 February 2016 at 14:11, Paolo Bonzini <pbonzini@redhat.com> wrote:
>> 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.
>>
>> Fixes: 5b82b70
>> Cc: Stefan Hajnoczi <stefanha@redhat.com>
>> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
>
> I've set the pre-merge tests running so I should be able
> to commit this to master first thing tomorrow.

Applied to master, thanks.

-- PMM
diff mbox

Patch

diff --git a/include/exec/ram_addr.h b/include/exec/ram_addr.h
index b1413a1..5d33def 100644
--- a/include/exec/ram_addr.h
+++ b/include/exec/ram_addr.h
@@ -121,6 +121,7 @@  static inline bool cpu_physical_memory_get_dirty(ram_addr_t start,
 {
     DirtyMemoryBlocks *blocks;
     unsigned long end, page;
+    unsigned long idx, offset, base;
     bool dirty = false;
 
     assert(client < DIRTY_MEMORY_NUM);
@@ -132,17 +133,22 @@  static inline bool cpu_physical_memory_get_dirty(ram_addr_t start,
 
     blocks = atomic_rcu_read(&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;
     }
 
     rcu_read_unlock();
@@ -156,6 +162,7 @@  static inline bool cpu_physical_memory_all_dirty(ram_addr_t start,
 {
     DirtyMemoryBlocks *blocks;
     unsigned long end, page;
+    unsigned long idx, offset, base;
     bool dirty = true;
 
     assert(client < DIRTY_MEMORY_NUM);
@@ -167,17 +174,22 @@  static inline bool cpu_physical_memory_all_dirty(ram_addr_t start,
 
     blocks = atomic_rcu_read(&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;
     }
 
     rcu_read_unlock();
@@ -248,6 +260,7 @@  static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
 {
     DirtyMemoryBlocks *blocks[DIRTY_MEMORY_NUM];
     unsigned long end, page;
+    unsigned long idx, offset, base;
     int i;
 
     if (!mask && !xen_enabled()) {
@@ -263,25 +276,29 @@  static inline void cpu_physical_memory_set_dirty_range(ram_addr_t start,
         blocks[i] = atomic_rcu_read(&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 (likely(mask & (1 << DIRTY_MEMORY_MIGRATION))) {
             bitmap_set_atomic(blocks[DIRTY_MEMORY_MIGRATION]->blocks[idx],
-                              offset, num);
+                              offset, next - page);
         }
         if (unlikely(mask & (1 << DIRTY_MEMORY_VGA))) {
             bitmap_set_atomic(blocks[DIRTY_MEMORY_VGA]->blocks[idx],
-                              offset, num);
+                              offset, next - page);
         }
         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;
     }
 
     rcu_read_unlock();