KVM: arm64: Enable ring-based dirty memory tracking
authorGavin Shan <gshan@redhat.com>
Thu, 10 Nov 2022 10:49:11 +0000 (18:49 +0800)
committerMarc Zyngier <maz@kernel.org>
Thu, 10 Nov 2022 13:11:58 +0000 (13:11 +0000)
Enable ring-based dirty memory tracking on ARM64:

  - Enable CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL.

  - Enable CONFIG_NEED_KVM_DIRTY_RING_WITH_BITMAP.

  - Set KVM_DIRTY_LOG_PAGE_OFFSET for the ring buffer's physical page
    offset.

  - Add ARM64 specific kvm_arch_allow_write_without_running_vcpu() to
    keep the site of saving vgic/its tables out of the no-running-vcpu
    radar.

Signed-off-by: Gavin Shan <gshan@redhat.com>
Signed-off-by: Marc Zyngier <maz@kernel.org>
Link: https://lore.kernel.org/r/20221110104914.31280-5-gshan@redhat.com
Documentation/virt/kvm/api.rst
arch/arm64/include/uapi/asm/kvm.h
arch/arm64/kvm/Kconfig
arch/arm64/kvm/arm.c
arch/arm64/kvm/vgic/vgic-its.c
include/kvm/arm_vgic.h

index 1f1b09aa6db47288d3916c8b37d40210cc4a16cd..773e4b202f47986936b7fb7ee5c8797c6f070fc8 100644 (file)
@@ -7921,7 +7921,7 @@ regardless of what has actually been exposed through the CPUID leaf.
 8.29 KVM_CAP_DIRTY_LOG_RING/KVM_CAP_DIRTY_LOG_RING_ACQ_REL
 ----------------------------------------------------------
 
-:Architectures: x86
+:Architectures: x86, arm64
 :Parameters: args[0] - size of the dirty log ring
 
 KVM is capable of tracking dirty memory using ring buffers that are
index 316917b9870704de245f002cb4261c46f8a2fea4..a7a857f1784d80d6264eeebecbeb371c7d13ba5b 100644 (file)
@@ -43,6 +43,7 @@
 #define __KVM_HAVE_VCPU_EVENTS
 
 #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
+#define KVM_DIRTY_LOG_PAGE_OFFSET 64
 
 #define KVM_REG_SIZE(id)                                               \
        (1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))
index 815cc118c675f3e0fc96e58df229ffe3f7ce928b..05da3c8f7e88f6a640ef744d8c401e695e490553 100644 (file)
@@ -32,6 +32,8 @@ menuconfig KVM
        select KVM_VFIO
        select HAVE_KVM_EVENTFD
        select HAVE_KVM_IRQFD
+       select HAVE_KVM_DIRTY_RING_ACQ_REL
+       select NEED_KVM_DIRTY_RING_WITH_BITMAP
        select HAVE_KVM_MSI
        select HAVE_KVM_IRQCHIP
        select HAVE_KVM_IRQ_ROUTING
index 94d33e296e10c57c34008af96d7a9adcb72d99ef..6b097605e38ceb8445c0b4d9ae9b9cda6a2c6b46 100644 (file)
@@ -746,6 +746,9 @@ static int check_vcpu_requests(struct kvm_vcpu *vcpu)
 
                if (kvm_check_request(KVM_REQ_SUSPEND, vcpu))
                        return kvm_vcpu_suspend(vcpu);
+
+               if (kvm_dirty_ring_check_request(vcpu))
+                       return 0;
        }
 
        return 1;
index 733b53055f9760fe01d22c3d28006c3a7cefae65..94a666dd1443d1310aadf35a1267e26d04709eca 100644 (file)
@@ -2743,6 +2743,7 @@ static int vgic_its_has_attr(struct kvm_device *dev,
 static int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr)
 {
        const struct vgic_its_abi *abi = vgic_its_get_abi(its);
+       struct vgic_dist *dist = &kvm->arch.vgic;
        int ret = 0;
 
        if (attr == KVM_DEV_ARM_VGIC_CTRL_INIT) /* Nothing to do */
@@ -2762,7 +2763,9 @@ static int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr)
                vgic_its_reset(kvm, its);
                break;
        case KVM_DEV_ARM_ITS_SAVE_TABLES:
+               dist->save_its_tables_in_progress = true;
                ret = abi->save_tables(its);
+               dist->save_its_tables_in_progress = false;
                break;
        case KVM_DEV_ARM_ITS_RESTORE_TABLES:
                ret = abi->restore_tables(its);
@@ -2775,6 +2778,23 @@ static int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr)
        return ret;
 }
 
+/*
+ * kvm_arch_allow_write_without_running_vcpu - allow writing guest memory
+ * without the running VCPU when dirty ring is enabled.
+ *
+ * The running VCPU is required to track dirty guest pages when dirty ring
+ * is enabled. Otherwise, the backup bitmap should be used to track the
+ * dirty guest pages. When vgic/its tables are being saved, the backup
+ * bitmap is used to track the dirty guest pages due to the missed running
+ * VCPU in the period.
+ */
+bool kvm_arch_allow_write_without_running_vcpu(struct kvm *kvm)
+{
+       struct vgic_dist *dist = &kvm->arch.vgic;
+
+       return dist->save_its_tables_in_progress;
+}
+
 static int vgic_its_set_attr(struct kvm_device *dev,
                             struct kvm_device_attr *attr)
 {
index 4df9e73a8bb5f28f66856a5c1cb6d02983ec3506..9270cd87da3fc806319bd1df08246b4879497582 100644 (file)
@@ -263,6 +263,7 @@ struct vgic_dist {
        struct vgic_io_device   dist_iodev;
 
        bool                    has_its;
+       bool                    save_its_tables_in_progress;
 
        /*
         * Contains the attributes and gpa of the LPI configuration table.
This page took 0.136582 seconds and 4 git commands to generate.