Commit 50e92b3c971129c96a5fffb51dd42691e2ee4004
Committed by
Avi Kivity
1 parent
f8275f9694
Exists in
master
and in
20 other branches
KVM: Fix __set_bit() race in mark_page_dirty() during dirty logging
It is possible that the __set_bit() in mark_page_dirty() is called simultaneously on the same region of memory, which may result in only one bit being set, because some callers do not take mmu_lock before mark_page_dirty(). This problem is hard to produce because when we reach mark_page_dirty() beginning from, e.g., tdp_page_fault(), mmu_lock is being held during __direct_map(): making kvm-unit-tests' dirty log api test write to two pages concurrently was not useful for this reason. So we have confirmed that there can actually be race condition by checking if some callers really reach there without holding mmu_lock using spin_is_locked(): probably they were from kvm_write_guest_page(). To fix this race, this patch changes the bit operation to the atomic version: note that nr_dirty_pages also suffers from the race but we do not need exactly correct numbers for now. Signed-off-by: Takuya Yoshikawa <yoshikawa.takuya@oss.ntt.co.jp> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Showing 1 changed file with 1 additions and 1 deletions Side-by-side Diff
virt/kvm/kvm_main.c
... | ... | @@ -1543,7 +1543,7 @@ |
1543 | 1543 | if (memslot && memslot->dirty_bitmap) { |
1544 | 1544 | unsigned long rel_gfn = gfn - memslot->base_gfn; |
1545 | 1545 | |
1546 | - if (!__test_and_set_bit_le(rel_gfn, memslot->dirty_bitmap)) | |
1546 | + if (!test_and_set_bit_le(rel_gfn, memslot->dirty_bitmap)) | |
1547 | 1547 | memslot->nr_dirty_pages++; |
1548 | 1548 | } |
1549 | 1549 | } |