KVM: Disable manual dirty log when dirty ring enabled

KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is for KVM_CLEAR_DIRTY_LOG, which is only
useful for KVM_GET_DIRTY_LOG.  Skip enabling it for kvm dirty ring.

More importantly, KVM_DIRTY_LOG_INITIALLY_SET will not wr-protect all the pages
initially, which is against how kvm dirty ring is used - there's no way for kvm
dirty ring to re-protect a page before it's notified as being written first
with a GFN entry in the ring!  So when KVM_DIRTY_LOG_INITIALLY_SET is enabled
with dirty ring, we'll see silent data loss after migration.

Signed-off-by: Peter Xu <peterx@redhat.com>
Message-Id: <20210506160549.130416-10-peterx@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
Peter Xu 2021-05-06 12:05:48 -04:00 committed by Paolo Bonzini
parent 2ea5cb0a47
commit a81a592698
1 changed files with 23 additions and 14 deletions

View File

@ -2131,20 +2131,29 @@ static int kvm_init(MachineState *ms)
s->coalesced_pio = s->coalesced_mmio && s->coalesced_pio = s->coalesced_mmio &&
kvm_check_extension(s, KVM_CAP_COALESCED_PIO); kvm_check_extension(s, KVM_CAP_COALESCED_PIO);
dirty_log_manual_caps = /*
kvm_check_extension(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2); * KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 is not needed when dirty ring is
dirty_log_manual_caps &= (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE | * enabled. More importantly, KVM_DIRTY_LOG_INITIALLY_SET will assume no
KVM_DIRTY_LOG_INITIALLY_SET); * page is wr-protected initially, which is against how kvm dirty ring is
s->manual_dirty_log_protect = dirty_log_manual_caps; * usage - kvm dirty ring requires all pages are wr-protected at the very
if (dirty_log_manual_caps) { * beginning. Enabling this feature for dirty ring causes data corruption.
ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0, */
dirty_log_manual_caps); if (!s->kvm_dirty_ring_size) {
if (ret) { dirty_log_manual_caps =
warn_report("Trying to enable capability %"PRIu64" of " kvm_check_extension(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2);
"KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 but failed. " dirty_log_manual_caps &= (KVM_DIRTY_LOG_MANUAL_PROTECT_ENABLE |
"Falling back to the legacy mode. ", KVM_DIRTY_LOG_INITIALLY_SET);
dirty_log_manual_caps); s->manual_dirty_log_protect = dirty_log_manual_caps;
s->manual_dirty_log_protect = 0; if (dirty_log_manual_caps) {
ret = kvm_vm_enable_cap(s, KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2, 0,
dirty_log_manual_caps);
if (ret) {
warn_report("Trying to enable capability %"PRIu64" of "
"KVM_CAP_MANUAL_DIRTY_LOG_PROTECT2 but failed. "
"Falling back to the legacy mode. ",
dirty_log_manual_caps);
s->manual_dirty_log_protect = 0;
}
} }
} }