History

mm: thp: KVM: Explicitly check for THP when populating secondary MMU

Add a helper, is_transparent_hugepage(), to explicitly check whether a compound page is a THP and use it when populating KVM's secondary MMU. The explicit check fixes a bug where a remapped compound page, e.g. for an XDP Rx socket, is mapped into a KVM guest and is mistaken for a THP, which results in KVM incorrectly creating a huge page in its secondary MMU.

Sean Christopherson committed 6 years ago

Commit 005ba371 parent 22b1d576 files · +31 −9Browse files

Unified · Split

6 files
  1. arch/x86/kvm/mmu/mmu.c +2 −2
  2. include/linux/huge_mm.h +6 −0
  3. include/linux/kvm_host.h +1 −0
  4. mm/huge_memory.c +11 −0
  5. virt/kvm/arm/mmu.c +1 −7
  6. virt/kvm/kvm_main.c +10 −0
arch/x86/kvm/mmu/mmu.c+2−2
@@ -3344,7 +3344,7 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu, · 3343 unmodified lines
3344 */3344 */
3345 if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn) &&3345 if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn) &&
3346 !kvm_is_zone_device_pfn(pfn) && level == PT_PAGE_TABLE_LEVEL &&3346 !kvm_is_zone_device_pfn(pfn) && level == PT_PAGE_TABLE_LEVEL &&
3347 PageTransCompoundMap(pfn_to_page(pfn))) {3347 kvm_is_transparent_hugepage(pfn)) {
3348 unsigned long mask;3348 unsigned long mask;
3349 3349
3350 /*3350 /*
@@ -5961,7 +5961,7 @@ restart: · 2610 unmodified lines
5961 */5961 */
5962 if (sp->role.direct && !kvm_is_reserved_pfn(pfn) &&5962 if (sp->role.direct && !kvm_is_reserved_pfn(pfn) &&
5963 !kvm_is_zone_device_pfn(pfn) &&5963 !kvm_is_zone_device_pfn(pfn) &&
5964 PageTransCompoundMap(pfn_to_page(pfn))) {5964 kvm_is_transparent_hugepage(pfn)) {
5965 pte_list_remove(rmap_head, sptep);5965 pte_list_remove(rmap_head, sptep);
5966 5966
5967 if (kvm_available_flush_tlb_with_range())5967 if (kvm_available_flush_tlb_with_range())
include/linux/huge_mm.h+6−0
@@ -160,6 +160,7 @@ extern unsigned long thp_get_unmapped_area(struct file *filp, · 159 unmodified lines
160 160
161extern void prep_transhuge_page(struct page *page);161extern void prep_transhuge_page(struct page *page);
162extern void free_transhuge_page(struct page *page);162extern void free_transhuge_page(struct page *page);
163bool is_transparent_hugepage(struct page *page);
163 164
164bool can_split_huge_page(struct page *page, int *pextra_pins);165bool can_split_huge_page(struct page *page, int *pextra_pins);
165int split_huge_page_to_list(struct page *page, struct list_head *list);166int split_huge_page_to_list(struct page *page, struct list_head *list);
@@ -308,6 +309,11 @@ static inline bool transhuge_vma_suitable(struct vm_area_struct *vma, · 142 unmodified lines
308 309
309static inline void prep_transhuge_page(struct page *page) {}310static inline void prep_transhuge_page(struct page *page) {}
310 311
312static inline bool is_transparent_hugepage(struct page *page)
313{
314 return false;
315}
316
311#define transparent_hugepage_flags 0UL317#define transparent_hugepage_flags 0UL
312 318
313#define thp_get_unmapped_area NULL319#define thp_get_unmapped_area NULL
include/linux/kvm_host.h+1−0
@@ -976,6 +976,7 @@ int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu); · 975 unmodified lines
976 976
977bool kvm_is_reserved_pfn(kvm_pfn_t pfn);977bool kvm_is_reserved_pfn(kvm_pfn_t pfn);
978bool kvm_is_zone_device_pfn(kvm_pfn_t pfn);978bool kvm_is_zone_device_pfn(kvm_pfn_t pfn);
979bool kvm_is_transparent_hugepage(kvm_pfn_t pfn);
979 980
980struct kvm_irq_ack_notifier {981struct kvm_irq_ack_notifier {
981 struct hlist_node link;982 struct hlist_node link;
mm/huge_memory.c+11−0
@@ -527,6 +527,17 @@ void prep_transhuge_page(struct page *page) · 526 unmodified lines
527 set_compound_page_dtor(page, TRANSHUGE_PAGE_DTOR);527 set_compound_page_dtor(page, TRANSHUGE_PAGE_DTOR);
528}528}
529 529
530bool is_transparent_hugepage(struct page *page)
531{
532 if (!PageCompound(page))
533 return 0;
534
535 page = compound_head(page);
536 return is_huge_zero_page(page) ||
537 page[1].compound_dtor == TRANSHUGE_PAGE_DTOR;
538}
539EXPORT_SYMBOL_GPL(is_transparent_hugepage);
540
530static unsigned long __thp_get_unmapped_area(struct file *filp, unsigned long len,541static unsigned long __thp_get_unmapped_area(struct file *filp, unsigned long len,
531 loff_t off, unsigned long flags, unsigned long size)542 loff_t off, unsigned long flags, unsigned long size)
532{543{
virt/kvm/arm/mmu.c+1−7
@@ -1377,14 +1377,8 @@ static bool transparent_hugepage_adjust(kvm_pfn_t *pfnp, phys_addr_t *ipap) · 1376 unmodified lines
1377{1377{
1378 kvm_pfn_t pfn = *pfnp;1378 kvm_pfn_t pfn = *pfnp;
1379 gfn_t gfn = *ipap >> PAGE_SHIFT;1379 gfn_t gfn = *ipap >> PAGE_SHIFT;
1380 struct page *page = pfn_to_page(pfn);
1381 1380
1382 /*1381 if (kvm_is_transparent_hugepage(pfn)) {
1383 * PageTransCompoundMap() returns true for THP and
1384 * hugetlbfs. Make sure the adjustment is done only for THP
1385 * pages.
1386 */
1387 if (!PageHuge(page) && PageTransCompoundMap(page)) {
1388 unsigned long mask;1382 unsigned long mask;
1389 /*1383 /*
1390 * The address we faulted on is backed by a transparent huge1384 * The address we faulted on is backed by a transparent huge
virt/kvm/kvm_main.c+10−0
@@ -191,6 +191,16 @@ bool kvm_is_reserved_pfn(kvm_pfn_t pfn) · 190 unmodified lines
191 return true;191 return true;
192}192}
193 193
194bool kvm_is_transparent_hugepage(kvm_pfn_t pfn)
195{
196 struct page *page = pfn_to_page(pfn);
197
198 if (!PageTransCompoundMap(page))
199 return false;
200
201 return is_transparent_hugepage(compound_head(page));
202}
203
194/*204/*
195 * Switches to specified vcpu, until a matching vcpu_put()205 * Switches to specified vcpu, until a matching vcpu_put()
196 */206 */