Commit 250012dd authored by Marc Zyngier's avatar Marc Zyngier
Browse files

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: default avatarMarc Zyngier <maz@kernel.org>
parents bb0cca24 4b3402f1
Loading
Loading
Loading
Loading
+15 −2
Original line number Diff line number Diff line
@@ -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
--------------------

+2 −1
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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

+5 −3
Original line number Diff line number Diff line
@@ -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,
+4 −1
Original line number Diff line number Diff line
@@ -82,6 +82,9 @@ unsigned int kvm_check_cap(long cap)

void vm_enable_dirty_ring(struct kvm_vm *vm, uint32_t 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;
}
Loading