Skip to content

Commit 8929bc9

Browse files
author
Marc Zyngier
committed
KVM: Use acquire/release semantics when accessing dirty ring GFN state
The current implementation of the dirty ring has an implicit requirement that stores to the dirty ring from userspace must be: - be ordered with one another - visible from another CPU executing a ring reset While these implicit requirements work well for x86 (and any other TSO-like architecture), they do not work for more relaxed architectures such as arm64 where stores to different addresses can be freely reordered, and loads from these addresses not observing writes from another CPU unless the required barriers (or acquire/release semantics) are used. In order to start fixing this, upgrade the ring reset accesses: - the kvm_dirty_gfn_harvested() helper now uses acquire semantics so it is ordered after all previous writes, including that from userspace - the kvm_dirty_gfn_set_invalid() helper now uses release semantics so that the next_slot and next_offset reads don't drift past the entry invalidation This is only a partial fix as the userspace side also need upgrading. Signed-off-by: Marc Zyngier <[email protected]> Reviewed-by: Gavin Shan <[email protected]> Reviewed-by: Peter Xu <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent b90cb10 commit 8929bc9

File tree

1 file changed

+2
-2
lines changed

1 file changed

+2
-2
lines changed

virt/kvm/dirty_ring.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ int kvm_dirty_ring_alloc(struct kvm_dirty_ring *ring, int index, u32 size)
7474

7575
static inline void kvm_dirty_gfn_set_invalid(struct kvm_dirty_gfn *gfn)
7676
{
77-
gfn->flags = 0;
77+
smp_store_release(&gfn->flags, 0);
7878
}
7979

8080
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)
8484

8585
static inline bool kvm_dirty_gfn_harvested(struct kvm_dirty_gfn *gfn)
8686
{
87-
return gfn->flags & KVM_DIRTY_GFN_F_RESET;
87+
return smp_load_acquire(&gfn->flags) & KVM_DIRTY_GFN_F_RESET;
8888
}
8989

9090
int kvm_dirty_ring_reset(struct kvm *kvm, struct kvm_dirty_ring *ring)

0 commit comments

Comments
 (0)