Skip to content

Commit 3039bcc

Browse files
sean-jcbonzini
authored andcommitted
KVM: Move x86's MMU notifier memslot walkers to generic code
Move the hva->gfn lookup for MMU notifiers into common code. Every arch does a similar lookup, and some arch code is all but identical across multiple architectures. In addition to consolidating code, this will allow introducing optimizations that will benefit all architectures without incurring multiple walks of the memslots, e.g. by taking mmu_lock if and only if a relevant range exists in the memslots. The use of __always_inline to avoid indirect call retpolines, as done by x86, may also benefit other architectures. Consolidating the lookups also fixes a wart in x86, where the legacy MMU and TDP MMU each do their own memslot walks. Lastly, future enhancements to the memslot implementation, e.g. to add an interval tree to track host address, will need to touch far less arch specific code. MIPS, PPC, and arm64 will be converted one at a time in future patches. Signed-off-by: Sean Christopherson <[email protected]> Message-Id: <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent c13fda2 commit 3039bcc

File tree

6 files changed

+314
-246
lines changed

6 files changed

+314
-246
lines changed

arch/x86/include/asm/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,6 +1727,7 @@ asmlinkage void kvm_spurious_fault(void);
17271727
_ASM_EXTABLE(666b, 667b)
17281728

17291729
#define KVM_ARCH_WANT_MMU_NOTIFIER
1730+
#define KVM_ARCH_WANT_NEW_MMU_NOTIFIER_APIS
17301731

17311732
int kvm_cpu_has_injectable_intr(struct kvm_vcpu *v);
17321733
int kvm_cpu_has_interrupt(struct kvm_vcpu *vcpu);

arch/x86/kvm/mmu/mmu.c

Lines changed: 47 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -1298,26 +1298,25 @@ static bool kvm_zap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
12981298
return flush;
12991299
}
13001300

1301-
static int kvm_unmap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
1302-
struct kvm_memory_slot *slot, gfn_t gfn, int level,
1303-
unsigned long data)
1301+
static bool kvm_unmap_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
1302+
struct kvm_memory_slot *slot, gfn_t gfn, int level,
1303+
pte_t unused)
13041304
{
13051305
return kvm_zap_rmapp(kvm, rmap_head, slot);
13061306
}
13071307

1308-
static int kvm_set_pte_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
1309-
struct kvm_memory_slot *slot, gfn_t gfn, int level,
1310-
unsigned long data)
1308+
static bool kvm_set_pte_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
1309+
struct kvm_memory_slot *slot, gfn_t gfn, int level,
1310+
pte_t pte)
13111311
{
13121312
u64 *sptep;
13131313
struct rmap_iterator iter;
13141314
int need_flush = 0;
13151315
u64 new_spte;
1316-
pte_t *ptep = (pte_t *)data;
13171316
kvm_pfn_t new_pfn;
13181317

1319-
WARN_ON(pte_huge(*ptep));
1320-
new_pfn = pte_pfn(*ptep);
1318+
WARN_ON(pte_huge(pte));
1319+
new_pfn = pte_pfn(pte);
13211320

13221321
restart:
13231322
for_each_rmap_spte(rmap_head, &iter, sptep) {
@@ -1326,7 +1325,7 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
13261325

13271326
need_flush = 1;
13281327

1329-
if (pte_write(*ptep)) {
1328+
if (pte_write(pte)) {
13301329
pte_list_remove(rmap_head, sptep);
13311330
goto restart;
13321331
} else {
@@ -1414,86 +1413,52 @@ static void slot_rmap_walk_next(struct slot_rmap_walk_iterator *iterator)
14141413
slot_rmap_walk_okay(_iter_); \
14151414
slot_rmap_walk_next(_iter_))
14161415

1417-
typedef int (*rmap_handler_t)(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
1418-
struct kvm_memory_slot *slot, gfn_t gfn,
1419-
int level, unsigned long data);
1416+
typedef bool (*rmap_handler_t)(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
1417+
struct kvm_memory_slot *slot, gfn_t gfn,
1418+
int level, pte_t pte);
14201419

1421-
static __always_inline int kvm_handle_hva_range(struct kvm *kvm,
1422-
unsigned long start,
1423-
unsigned long end,
1424-
unsigned long data,
1425-
rmap_handler_t handler)
1420+
static __always_inline bool kvm_handle_gfn_range(struct kvm *kvm,
1421+
struct kvm_gfn_range *range,
1422+
rmap_handler_t handler)
14261423
{
1427-
struct kvm_memslots *slots;
1428-
struct kvm_memory_slot *memslot;
14291424
struct slot_rmap_walk_iterator iterator;
1430-
int ret = 0;
1431-
int i;
1432-
1433-
for (i = 0; i < KVM_ADDRESS_SPACE_NUM; i++) {
1434-
slots = __kvm_memslots(kvm, i);
1435-
kvm_for_each_memslot(memslot, slots) {
1436-
unsigned long hva_start, hva_end;
1437-
gfn_t gfn_start, gfn_end;
1425+
bool ret = false;
14381426

1439-
hva_start = max(start, memslot->userspace_addr);
1440-
hva_end = min(end, memslot->userspace_addr +
1441-
(memslot->npages << PAGE_SHIFT));
1442-
if (hva_start >= hva_end)
1443-
continue;
1444-
/*
1445-
* {gfn(page) | page intersects with [hva_start, hva_end)} =
1446-
* {gfn_start, gfn_start+1, ..., gfn_end-1}.
1447-
*/
1448-
gfn_start = hva_to_gfn_memslot(hva_start, memslot);
1449-
gfn_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot);
1450-
1451-
for_each_slot_rmap_range(memslot, PG_LEVEL_4K,
1452-
KVM_MAX_HUGEPAGE_LEVEL,
1453-
gfn_start, gfn_end - 1,
1454-
&iterator)
1455-
ret |= handler(kvm, iterator.rmap, memslot,
1456-
iterator.gfn, iterator.level, data);
1457-
}
1458-
}
1427+
for_each_slot_rmap_range(range->slot, PG_LEVEL_4K, KVM_MAX_HUGEPAGE_LEVEL,
1428+
range->start, range->end - 1, &iterator)
1429+
ret |= handler(kvm, iterator.rmap, range->slot, iterator.gfn,
1430+
iterator.level, range->pte);
14591431

14601432
return ret;
14611433
}
14621434

1463-
static int kvm_handle_hva(struct kvm *kvm, unsigned long hva,
1464-
unsigned long data, rmap_handler_t handler)
1435+
bool kvm_unmap_gfn_range(struct kvm *kvm, struct kvm_gfn_range *range)
14651436
{
1466-
return kvm_handle_hva_range(kvm, hva, hva + 1, data, handler);
1467-
}
1468-
1469-
int kvm_unmap_hva_range(struct kvm *kvm, unsigned long start, unsigned long end,
1470-
unsigned flags)
1471-
{
1472-
int r;
1437+
bool flush;
14731438

1474-
r = kvm_handle_hva_range(kvm, start, end, 0, kvm_unmap_rmapp);
1439+
flush = kvm_handle_gfn_range(kvm, range, kvm_unmap_rmapp);
14751440

14761441
if (is_tdp_mmu_enabled(kvm))
1477-
r |= kvm_tdp_mmu_zap_hva_range(kvm, start, end);
1442+
flush |= kvm_tdp_mmu_unmap_gfn_range(kvm, range, flush);
14781443

1479-
return r;
1444+
return flush;
14801445
}
14811446

1482-
int kvm_set_spte_hva(struct kvm *kvm, unsigned long hva, pte_t pte)
1447+
bool kvm_set_spte_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
14831448
{
1484-
int r;
1449+
bool flush;
14851450

1486-
r = kvm_handle_hva(kvm, hva, (unsigned long)&pte, kvm_set_pte_rmapp);
1451+
flush = kvm_handle_gfn_range(kvm, range, kvm_set_pte_rmapp);
14871452

14881453
if (is_tdp_mmu_enabled(kvm))
1489-
r |= kvm_tdp_mmu_set_spte_hva(kvm, hva, &pte);
1454+
flush |= kvm_tdp_mmu_set_spte_gfn(kvm, range);
14901455

1491-
return r;
1456+
return flush;
14921457
}
14931458

1494-
static int kvm_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
1495-
struct kvm_memory_slot *slot, gfn_t gfn, int level,
1496-
unsigned long data)
1459+
static bool kvm_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
1460+
struct kvm_memory_slot *slot, gfn_t gfn, int level,
1461+
pte_t unused)
14971462
{
14981463
u64 *sptep;
14991464
struct rmap_iterator iter;
@@ -1505,9 +1470,9 @@ static int kvm_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
15051470
return young;
15061471
}
15071472

1508-
static int kvm_test_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
1509-
struct kvm_memory_slot *slot, gfn_t gfn,
1510-
int level, unsigned long data)
1473+
static bool kvm_test_age_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
1474+
struct kvm_memory_slot *slot, gfn_t gfn,
1475+
int level, pte_t unused)
15111476
{
15121477
u64 *sptep;
15131478
struct rmap_iterator iter;
@@ -1529,29 +1494,31 @@ static void rmap_recycle(struct kvm_vcpu *vcpu, u64 *spte, gfn_t gfn)
15291494

15301495
rmap_head = gfn_to_rmap(vcpu->kvm, gfn, sp);
15311496

1532-
kvm_unmap_rmapp(vcpu->kvm, rmap_head, NULL, gfn, sp->role.level, 0);
1497+
kvm_unmap_rmapp(vcpu->kvm, rmap_head, NULL, gfn, sp->role.level, __pte(0));
15331498
kvm_flush_remote_tlbs_with_address(vcpu->kvm, sp->gfn,
15341499
KVM_PAGES_PER_HPAGE(sp->role.level));
15351500
}
15361501

1537-
int kvm_age_hva(struct kvm *kvm, unsigned long start, unsigned long end)
1502+
bool kvm_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
15381503
{
1539-
int young = false;
1504+
bool young;
1505+
1506+
young = kvm_handle_gfn_range(kvm, range, kvm_age_rmapp);
15401507

1541-
young = kvm_handle_hva_range(kvm, start, end, 0, kvm_age_rmapp);
15421508
if (is_tdp_mmu_enabled(kvm))
1543-
young |= kvm_tdp_mmu_age_hva_range(kvm, start, end);
1509+
young |= kvm_tdp_mmu_age_gfn_range(kvm, range);
15441510

15451511
return young;
15461512
}
15471513

1548-
int kvm_test_age_hva(struct kvm *kvm, unsigned long hva)
1514+
bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
15491515
{
1550-
int young = false;
1516+
bool young;
1517+
1518+
young = kvm_handle_gfn_range(kvm, range, kvm_test_age_rmapp);
15511519

1552-
young = kvm_handle_hva(kvm, hva, 0, kvm_test_age_rmapp);
15531520
if (is_tdp_mmu_enabled(kvm))
1554-
young |= kvm_tdp_mmu_test_age_hva(kvm, hva);
1521+
young |= kvm_tdp_mmu_test_age_gfn(kvm, range);
15551522

15561523
return young;
15571524
}

0 commit comments

Comments
 (0)