Skip to content

Commit a937f37

Browse files
author
Marc Zyngier
committed
Merge branch kvm-arm64/dirty-ring into kvmarm-master/next
* kvm-arm64/dirty-ring: : . : Add support for the "per-vcpu dirty-ring tracking with a bitmap : and sprinkles on top", courtesy of Gavin Shan. : : This branch drags the kvmarm-fixes-6.1-3 tag which was already : merged in 6.1-rc4 so that the branch is in a working state. : . KVM: Push dirty information unconditionally to backup bitmap KVM: selftests: Automate choosing dirty ring size in dirty_log_test KVM: selftests: Clear dirty ring states between two modes in dirty_log_test KVM: selftests: Use host page size to map ring buffer in dirty_log_test KVM: arm64: Enable ring-based dirty memory tracking KVM: Support dirty ring in conjunction with bitmap KVM: Move declaration of kvm_cpu_dirty_log_size() to kvm_dirty_ring.h KVM: x86: Introduce KVM_REQ_DIRTY_RING_SOFT_FULL Signed-off-by: Marc Zyngier <[email protected]>
2 parents 3bbcc8c + c57351a commit a937f37

File tree

17 files changed

+227
-61
lines changed

17 files changed

+227
-61
lines changed

Documentation/virt/kvm/api.rst

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7921,7 +7921,7 @@ regardless of what has actually been exposed through the CPUID leaf.
79217921
8.29 KVM_CAP_DIRTY_LOG_RING/KVM_CAP_DIRTY_LOG_RING_ACQ_REL
79227922
----------------------------------------------------------
79237923

7924-
:Architectures: x86
7924+
:Architectures: x86, arm64
79257925
:Parameters: args[0] - size of the dirty log ring
79267926

79277927
KVM is capable of tracking dirty memory using ring buffers that are
@@ -8003,13 +8003,6 @@ flushing is done by the KVM_GET_DIRTY_LOG ioctl). To achieve that, one
80038003
needs to kick the vcpu out of KVM_RUN using a signal. The resulting
80048004
vmexit ensures that all dirty GFNs are flushed to the dirty rings.
80058005

8006-
NOTE: the capability KVM_CAP_DIRTY_LOG_RING and the corresponding
8007-
ioctl KVM_RESET_DIRTY_RINGS are mutual exclusive to the existing ioctls
8008-
KVM_GET_DIRTY_LOG and KVM_CLEAR_DIRTY_LOG. After enabling
8009-
KVM_CAP_DIRTY_LOG_RING with an acceptable dirty ring size, the virtual
8010-
machine will switch to ring-buffer dirty page tracking and further
8011-
KVM_GET_DIRTY_LOG or KVM_CLEAR_DIRTY_LOG ioctls will fail.
8012-
80138006
NOTE: KVM_CAP_DIRTY_LOG_RING_ACQ_REL is the only capability that
80148007
should be exposed by weakly ordered architecture, in order to indicate
80158008
the additional memory ordering requirements imposed on userspace when
@@ -8018,6 +8011,33 @@ Architecture with TSO-like ordering (such as x86) are allowed to
80188011
expose both KVM_CAP_DIRTY_LOG_RING and KVM_CAP_DIRTY_LOG_RING_ACQ_REL
80198012
to userspace.
80208013

8014+
After enabling the dirty rings, the userspace needs to detect the
8015+
capability of KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP to see whether the
8016+
ring structures can be backed by per-slot bitmaps. With this capability
8017+
advertised, it means the architecture can dirty guest pages without
8018+
vcpu/ring context, so that some of the dirty information will still be
8019+
maintained in the bitmap structure. KVM_CAP_DIRTY_LOG_RING_WITH_BITMAP
8020+
can't be enabled if the capability of KVM_CAP_DIRTY_LOG_RING_ACQ_REL
8021+
hasn't been enabled, or any memslot has been existing.
8022+
8023+
Note that the bitmap here is only a backup of the ring structure. The
8024+
use of the ring and bitmap combination is only beneficial if there is
8025+
only a very small amount of memory that is dirtied out of vcpu/ring
8026+
context. Otherwise, the stand-alone per-slot bitmap mechanism needs to
8027+
be considered.
8028+
8029+
To collect dirty bits in the backup bitmap, userspace can use the same
8030+
KVM_GET_DIRTY_LOG ioctl. KVM_CLEAR_DIRTY_LOG isn't needed as long as all
8031+
the generation of the dirty bits is done in a single pass. Collecting
8032+
the dirty bitmap should be the very last thing that the VMM does before
8033+
considering the state as complete. VMM needs to ensure that the dirty
8034+
state is final and avoid missing dirty pages from another ioctl ordered
8035+
after the bitmap collection.
8036+
8037+
NOTE: One example of using the backup bitmap is saving arm64 vgic/its
8038+
tables through KVM_DEV_ARM_{VGIC_GRP_CTRL, ITS_SAVE_TABLES} command on
8039+
KVM device "kvm-arm-vgic-its" when dirty ring is enabled.
8040+
80218041
8.30 KVM_CAP_XEN_HVM
80228042
--------------------
80238043

Documentation/virt/kvm/devices/arm-vgic-its.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ KVM_DEV_ARM_VGIC_GRP_CTRL
5252

5353
KVM_DEV_ARM_ITS_SAVE_TABLES
5454
save the ITS table data into guest RAM, at the location provisioned
55-
by the guest in corresponding registers/table entries.
55+
by the guest in corresponding registers/table entries. Should userspace
56+
require a form of dirty tracking to identify which pages are modified
57+
by the saving process, it should use a bitmap even if using another
58+
mechanism to track the memory dirtied by the vCPUs.
5659

5760
The layout of the tables in guest memory defines an ABI. The entries
5861
are laid out in little endian format as described in the last paragraph.

arch/arm64/include/uapi/asm/kvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#define __KVM_HAVE_VCPU_EVENTS
4444

4545
#define KVM_COALESCED_MMIO_PAGE_OFFSET 1
46+
#define KVM_DIRTY_LOG_PAGE_OFFSET 64
4647

4748
#define KVM_REG_SIZE(id) \
4849
(1U << (((id) & KVM_REG_SIZE_MASK) >> KVM_REG_SIZE_SHIFT))

arch/arm64/kvm/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ menuconfig KVM
3232
select KVM_VFIO
3333
select HAVE_KVM_EVENTFD
3434
select HAVE_KVM_IRQFD
35+
select HAVE_KVM_DIRTY_RING_ACQ_REL
36+
select NEED_KVM_DIRTY_RING_WITH_BITMAP
3537
select HAVE_KVM_MSI
3638
select HAVE_KVM_IRQCHIP
3739
select HAVE_KVM_IRQ_ROUTING

arch/arm64/kvm/arm.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,9 @@ static int check_vcpu_requests(struct kvm_vcpu *vcpu)
746746

747747
if (kvm_check_request(KVM_REQ_SUSPEND, vcpu))
748748
return kvm_vcpu_suspend(vcpu);
749+
750+
if (kvm_dirty_ring_check_request(vcpu))
751+
return 0;
749752
}
750753

751754
return 1;

arch/arm64/kvm/vgic/vgic-its.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2743,6 +2743,7 @@ static int vgic_its_has_attr(struct kvm_device *dev,
27432743
static int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr)
27442744
{
27452745
const struct vgic_its_abi *abi = vgic_its_get_abi(its);
2746+
struct vgic_dist *dist = &kvm->arch.vgic;
27462747
int ret = 0;
27472748

27482749
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)
27622763
vgic_its_reset(kvm, its);
27632764
break;
27642765
case KVM_DEV_ARM_ITS_SAVE_TABLES:
2766+
dist->save_its_tables_in_progress = true;
27652767
ret = abi->save_tables(its);
2768+
dist->save_its_tables_in_progress = false;
27662769
break;
27672770
case KVM_DEV_ARM_ITS_RESTORE_TABLES:
27682771
ret = abi->restore_tables(its);
@@ -2775,6 +2778,23 @@ static int vgic_its_ctrl(struct kvm *kvm, struct vgic_its *its, u64 attr)
27752778
return ret;
27762779
}
27772780

2781+
/*
2782+
* kvm_arch_allow_write_without_running_vcpu - allow writing guest memory
2783+
* without the running VCPU when dirty ring is enabled.
2784+
*
2785+
* The running VCPU is required to track dirty guest pages when dirty ring
2786+
* is enabled. Otherwise, the backup bitmap should be used to track the
2787+
* dirty guest pages. When vgic/its tables are being saved, the backup
2788+
* bitmap is used to track the dirty guest pages due to the missed running
2789+
* VCPU in the period.
2790+
*/
2791+
bool kvm_arch_allow_write_without_running_vcpu(struct kvm *kvm)
2792+
{
2793+
struct vgic_dist *dist = &kvm->arch.vgic;
2794+
2795+
return dist->save_its_tables_in_progress;
2796+
}
2797+
27782798
static int vgic_its_set_attr(struct kvm_device *dev,
27792799
struct kvm_device_attr *attr)
27802800
{

arch/x86/include/asm/kvm_host.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,8 +2090,6 @@ static inline int kvm_cpu_get_apicid(int mps_cpu)
20902090
#define GET_SMSTATE(type, buf, offset) \
20912091
(*(type *)((buf) + (offset) - 0x7e00))
20922092

2093-
int kvm_cpu_dirty_log_size(void);
2094-
20952093
int memslot_rmap_alloc(struct kvm_memory_slot *slot, unsigned long npages);
20962094

20972095
#define KVM_CLOCK_VALID_FLAGS \

arch/x86/kvm/x86.c

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10515,20 +10515,17 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
1051510515

1051610516
bool req_immediate_exit = false;
1051710517

10518-
/* Forbid vmenter if vcpu dirty ring is soft-full */
10519-
if (unlikely(vcpu->kvm->dirty_ring_size &&
10520-
kvm_dirty_ring_soft_full(&vcpu->dirty_ring))) {
10521-
vcpu->run->exit_reason = KVM_EXIT_DIRTY_RING_FULL;
10522-
trace_kvm_dirty_ring_exit(vcpu);
10523-
r = 0;
10524-
goto out;
10525-
}
10526-
1052710518
if (kvm_request_pending(vcpu)) {
1052810519
if (kvm_check_request(KVM_REQ_VM_DEAD, vcpu)) {
1052910520
r = -EIO;
1053010521
goto out;
1053110522
}
10523+
10524+
if (kvm_dirty_ring_check_request(vcpu)) {
10525+
r = 0;
10526+
goto out;
10527+
}
10528+
1053210529
if (kvm_check_request(KVM_REQ_GET_NESTED_STATE_PAGES, vcpu)) {
1053310530
if (unlikely(!kvm_x86_ops.nested_ops->get_nested_state_pages(vcpu))) {
1053410531
r = 0;

include/kvm/arm_vgic.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ struct vgic_dist {
263263
struct vgic_io_device dist_iodev;
264264

265265
bool has_its;
266+
bool save_its_tables_in_progress;
266267

267268
/*
268269
* Contains the attributes and gpa of the LPI configuration table.

include/linux/kvm_dirty_ring.h

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ static inline u32 kvm_dirty_ring_get_rsvd_entries(void)
3737
return 0;
3838
}
3939

40+
static inline bool kvm_use_dirty_bitmap(struct kvm *kvm)
41+
{
42+
return true;
43+
}
44+
4045
static inline int kvm_dirty_ring_alloc(struct kvm_dirty_ring *ring,
4146
int index, u32 size)
4247
{
@@ -49,7 +54,7 @@ static inline int kvm_dirty_ring_reset(struct kvm *kvm,
4954
return 0;
5055
}
5156

52-
static inline void kvm_dirty_ring_push(struct kvm_dirty_ring *ring,
57+
static inline void kvm_dirty_ring_push(struct kvm_vcpu *vcpu,
5358
u32 slot, u64 offset)
5459
{
5560
}
@@ -64,13 +69,11 @@ static inline void kvm_dirty_ring_free(struct kvm_dirty_ring *ring)
6469
{
6570
}
6671

67-
static inline bool kvm_dirty_ring_soft_full(struct kvm_dirty_ring *ring)
68-
{
69-
return true;
70-
}
71-
7272
#else /* CONFIG_HAVE_KVM_DIRTY_RING */
7373

74+
int kvm_cpu_dirty_log_size(void);
75+
bool kvm_use_dirty_bitmap(struct kvm *kvm);
76+
bool kvm_arch_allow_write_without_running_vcpu(struct kvm *kvm);
7477
u32 kvm_dirty_ring_get_rsvd_entries(void);
7578
int kvm_dirty_ring_alloc(struct kvm_dirty_ring *ring, int index, u32 size);
7679

@@ -84,13 +87,14 @@ int kvm_dirty_ring_reset(struct kvm *kvm, struct kvm_dirty_ring *ring);
8487
* returns =0: successfully pushed
8588
* <0: unable to push, need to wait
8689
*/
87-
void kvm_dirty_ring_push(struct kvm_dirty_ring *ring, u32 slot, u64 offset);
90+
void kvm_dirty_ring_push(struct kvm_vcpu *vcpu, u32 slot, u64 offset);
91+
92+
bool kvm_dirty_ring_check_request(struct kvm_vcpu *vcpu);
8893

8994
/* for use in vm_operations_struct */
9095
struct page *kvm_dirty_ring_get_page(struct kvm_dirty_ring *ring, u32 offset);
9196

9297
void kvm_dirty_ring_free(struct kvm_dirty_ring *ring);
93-
bool kvm_dirty_ring_soft_full(struct kvm_dirty_ring *ring);
9498

9599
#endif /* CONFIG_HAVE_KVM_DIRTY_RING */
96100

0 commit comments

Comments
 (0)