Merge branch kvm-arm64/dirty-log-ordered into kvmarm-master/next
* kvm-arm64/dirty-log-ordered: : . : Retrofit some ordering into the existing API dirty-ring by: : : - relying on acquire/release semantics which are the default on x86, : but need to be explicit on arm64 : : - adding a new capability that indicate which flavor is supported, either : with explicit ordering (arm64) or both implicit and explicit (x86), : as suggested by Paolo at KVM Forum : : - documenting the requirements for this new capability on weakly ordered : architectures : : - updating the selftests to do the right thing : . KVM: selftests: dirty-log: Use KVM_CAP_DIRTY_LOG_RING_ACQ_REL if available KVM: selftests: dirty-log: Upgrade flag accesses to acquire/release semantics KVM: Document weakly ordered architecture requirements for dirty ring KVM: x86: Select CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL KVM: Add KVM_CAP_DIRTY_LOG_RING_ACQ_REL capability and config option KVM: Use acquire/release semantics when accessing dirty ring GFN state Signed-off-by: Marc Zyngier <maz@kernel.org>
This commit is contained in:
commit
250012dd58
|
@ -8019,8 +8019,8 @@ guest according to the bits in the KVM_CPUID_FEATURES CPUID leaf
|
|||
(0x40000001). Otherwise, a guest may use the paravirtual features
|
||||
regardless of what has actually been exposed through the CPUID leaf.
|
||||
|
||||
8.29 KVM_CAP_DIRTY_LOG_RING
|
||||
---------------------------
|
||||
8.29 KVM_CAP_DIRTY_LOG_RING/KVM_CAP_DIRTY_LOG_RING_ACQ_REL
|
||||
----------------------------------------------------------
|
||||
|
||||
:Architectures: x86
|
||||
:Parameters: args[0] - size of the dirty log ring
|
||||
|
@ -8078,6 +8078,11 @@ on to the next GFN. The userspace should continue to do this until the
|
|||
flags of a GFN have the DIRTY bit cleared, meaning that it has harvested
|
||||
all the dirty GFNs that were available.
|
||||
|
||||
Note that on weakly ordered architectures, userspace accesses to the
|
||||
ring buffer (and more specifically the 'flags' field) must be ordered,
|
||||
using load-acquire/store-release accessors when available, or any
|
||||
other memory barrier that will ensure this ordering.
|
||||
|
||||
It's not necessary for userspace to harvest the all dirty GFNs at once.
|
||||
However it must collect the dirty GFNs in sequence, i.e., the userspace
|
||||
program cannot skip one dirty GFN to collect the one next to it.
|
||||
|
@ -8106,6 +8111,14 @@ KVM_CAP_DIRTY_LOG_RING with an acceptable dirty ring size, the virtual
|
|||
machine will switch to ring-buffer dirty page tracking and further
|
||||
KVM_GET_DIRTY_LOG or KVM_CLEAR_DIRTY_LOG ioctls will fail.
|
||||
|
||||
NOTE: KVM_CAP_DIRTY_LOG_RING_ACQ_REL is the only capability that
|
||||
should be exposed by weakly ordered architecture, in order to indicate
|
||||
the additional memory ordering requirements imposed on userspace when
|
||||
reading the state of an entry and mutating it from DIRTY to HARVESTED.
|
||||
Architecture with TSO-like ordering (such as x86) are allowed to
|
||||
expose both KVM_CAP_DIRTY_LOG_RING and KVM_CAP_DIRTY_LOG_RING_ACQ_REL
|
||||
to userspace.
|
||||
|
||||
8.30 KVM_CAP_XEN_HVM
|
||||
--------------------
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ config KVM
|
|||
select HAVE_KVM_IRQCHIP
|
||||
select HAVE_KVM_PFNCACHE
|
||||
select HAVE_KVM_IRQFD
|
||||
select HAVE_KVM_DIRTY_RING
|
||||
select HAVE_KVM_DIRTY_RING_TSO
|
||||
select HAVE_KVM_DIRTY_RING_ACQ_REL
|
||||
select IRQ_BYPASS_MANAGER
|
||||
select HAVE_KVM_IRQ_BYPASS
|
||||
select HAVE_KVM_IRQ_ROUTING
|
||||
|
|
|
@ -1177,6 +1177,7 @@ struct kvm_ppc_resize_hpt {
|
|||
#define KVM_CAP_VM_DISABLE_NX_HUGE_PAGES 220
|
||||
#define KVM_CAP_S390_ZPCI_OP 221
|
||||
#define KVM_CAP_S390_CPU_TOPOLOGY 222
|
||||
#define KVM_CAP_DIRTY_LOG_RING_ACQ_REL 223
|
||||
|
||||
#ifdef KVM_CAP_IRQ_ROUTING
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <asm/barrier.h>
|
||||
|
||||
#include "kvm_util.h"
|
||||
#include "test_util.h"
|
||||
|
@ -264,7 +265,8 @@ static void default_after_vcpu_run(struct kvm_vcpu *vcpu, int ret, int err)
|
|||
|
||||
static bool dirty_ring_supported(void)
|
||||
{
|
||||
return kvm_has_cap(KVM_CAP_DIRTY_LOG_RING);
|
||||
return (kvm_has_cap(KVM_CAP_DIRTY_LOG_RING) ||
|
||||
kvm_has_cap(KVM_CAP_DIRTY_LOG_RING_ACQ_REL));
|
||||
}
|
||||
|
||||
static void dirty_ring_create_vm_done(struct kvm_vm *vm)
|
||||
|
@ -279,12 +281,12 @@ static void dirty_ring_create_vm_done(struct kvm_vm *vm)
|
|||
|
||||
static inline bool dirty_gfn_is_dirtied(struct kvm_dirty_gfn *gfn)
|
||||
{
|
||||
return gfn->flags == KVM_DIRTY_GFN_F_DIRTY;
|
||||
return smp_load_acquire(&gfn->flags) == KVM_DIRTY_GFN_F_DIRTY;
|
||||
}
|
||||
|
||||
static inline void dirty_gfn_set_collected(struct kvm_dirty_gfn *gfn)
|
||||
{
|
||||
gfn->flags = KVM_DIRTY_GFN_F_RESET;
|
||||
smp_store_release(&gfn->flags, KVM_DIRTY_GFN_F_RESET);
|
||||
}
|
||||
|
||||
static uint32_t dirty_ring_collect_one(struct kvm_dirty_gfn *dirty_gfns,
|
||||
|
|
|
@ -82,7 +82,10 @@ unsigned int kvm_check_cap(long cap)
|
|||
|
||||
void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t ring_size)
|
||||
{
|
||||
vm_enable_cap(vm, KVM_CAP_DIRTY_LOG_RING, ring_size);
|
||||
if (vm_check_cap(vm, KVM_CAP_DIRTY_LOG_RING_ACQ_REL))
|
||||
vm_enable_cap(vm, KVM_CAP_DIRTY_LOG_RING_ACQ_REL, ring_size);
|
||||
else
|
||||
vm_enable_cap(vm, KVM_CAP_DIRTY_LOG_RING, ring_size);
|
||||
vm->dirty_ring_size = ring_size;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,20 @@ config HAVE_KVM_IRQ_ROUTING
|
|||
config HAVE_KVM_DIRTY_RING
|
||||
bool
|
||||
|
||||
# Only strongly ordered architectures can select this, as it doesn't
|
||||
# put any explicit constraint on userspace ordering. They can also
|
||||
# select the _ACQ_REL version.
|
||||
config HAVE_KVM_DIRTY_RING_TSO
|
||||
bool
|
||||
select HAVE_KVM_DIRTY_RING
|
||||
depends on X86
|
||||
|
||||
# Weakly ordered architectures can only select this, advertising
|
||||
# to userspace the additional ordering requirements.
|
||||
config HAVE_KVM_DIRTY_RING_ACQ_REL
|
||||
bool
|
||||
select HAVE_KVM_DIRTY_RING
|
||||
|
||||
config HAVE_KVM_EVENTFD
|
||||
bool
|
||||
select EVENTFD
|
||||
|
|
|
@ -74,7 +74,7 @@ int kvm_dirty_ring_alloc(struct kvm_dirty_ring *ring, int index, u32 size)
|
|||
|
||||
static inline void kvm_dirty_gfn_set_invalid(struct kvm_dirty_gfn *gfn)
|
||||
{
|
||||
gfn->flags = 0;
|
||||
smp_store_release(&gfn->flags, 0);
|
||||
}
|
||||
|
||||
static inline void kvm_dirty_gfn_set_dirtied(struct kvm_dirty_gfn *gfn)
|
||||
|
@ -84,7 +84,7 @@ static inline void kvm_dirty_gfn_set_dirtied(struct kvm_dirty_gfn *gfn)
|
|||
|
||||
static inline bool kvm_dirty_gfn_harvested(struct kvm_dirty_gfn *gfn)
|
||||
{
|
||||
return gfn->flags & KVM_DIRTY_GFN_F_RESET;
|
||||
return smp_load_acquire(&gfn->flags) & KVM_DIRTY_GFN_F_RESET;
|
||||
}
|
||||
|
||||
int kvm_dirty_ring_reset(struct kvm *kvm, struct kvm_dirty_ring *ring)
|
||||
|
|
|
@ -4475,7 +4475,13 @@ static long kvm_vm_ioctl_check_extension_generic(struct kvm *kvm, long arg)
|
|||
case KVM_CAP_NR_MEMSLOTS:
|
||||
return KVM_USER_MEM_SLOTS;
|
||||
case KVM_CAP_DIRTY_LOG_RING:
|
||||
#ifdef CONFIG_HAVE_KVM_DIRTY_RING
|
||||
#ifdef CONFIG_HAVE_KVM_DIRTY_RING_TSO
|
||||
return KVM_DIRTY_RING_MAX_ENTRIES * sizeof(struct kvm_dirty_gfn);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
case KVM_CAP_DIRTY_LOG_RING_ACQ_REL:
|
||||
#ifdef CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL
|
||||
return KVM_DIRTY_RING_MAX_ENTRIES * sizeof(struct kvm_dirty_gfn);
|
||||
#else
|
||||
return 0;
|
||||
|
@ -4580,6 +4586,7 @@ static int kvm_vm_ioctl_enable_cap_generic(struct kvm *kvm,
|
|||
return 0;
|
||||
}
|
||||
case KVM_CAP_DIRTY_LOG_RING:
|
||||
case KVM_CAP_DIRTY_LOG_RING_ACQ_REL:
|
||||
return kvm_vm_ioctl_enable_dirty_log_ring(kvm, cap->args[0]);
|
||||
default:
|
||||
return kvm_vm_ioctl_enable_cap(kvm, cap);
|
||||
|
|
Loading…
Reference in New Issue