Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

KVM: s390: Add alignment checks for hugepages

When backing a guest page with a large page, check that the alignment
of the guest page matches the alignment of the host physical page
backing it within the large page.

Also check that the memslot is large enough to fit the large page.

Those checks are currently not needed, because memslots are guaranteed
to be 1m-aligned, but this will change.

Reviewed-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Claudio Imbrenda <imbrenda@linux.ibm.com>

+29 -8
+1 -1
arch/s390/kvm/faultin.c
··· 109 109 scoped_guard(read_lock, &kvm->mmu_lock) { 110 110 if (!mmu_invalidate_retry_gfn(kvm, inv_seq, f->gfn)) { 111 111 f->valid = true; 112 - rc = gmap_link(mc, kvm->arch.gmap, f); 112 + rc = gmap_link(mc, kvm->arch.gmap, f, slot); 113 113 kvm_release_faultin_page(kvm, f->page, !!rc, f->write_attempt); 114 114 f->page = NULL; 115 115 }
+26 -6
arch/s390/kvm/gmap.c
··· 613 613 return rc; 614 614 } 615 615 616 - static inline bool gmap_2g_allowed(struct gmap *gmap, gfn_t gfn) 616 + static inline bool gmap_2g_allowed(struct gmap *gmap, struct guest_fault *f, 617 + struct kvm_memory_slot *slot) 617 618 { 618 619 return false; 619 620 } 620 621 621 - static inline bool gmap_1m_allowed(struct gmap *gmap, gfn_t gfn) 622 + /** 623 + * gmap_1m_allowed() - Check whether a 1M hugepage is allowed. 624 + * @gmap: The gmap of the guest. 625 + * @f: Describes the fault that is being resolved. 626 + * @slot: The memslot the faulting address belongs to. 627 + * 628 + * The function checks whether the GMAP_FLAG_ALLOW_HPAGE_1M flag is set for 629 + * @gmap, whether the offset of the address in the 1M virtual frame is the 630 + * same as the offset in the physical 1M frame, and finally whether the whole 631 + * 1M page would fit in the given memslot. 632 + * 633 + * Return: true if a 1M hugepage is allowed to back the faulting address, false 634 + * otherwise. 635 + */ 636 + static inline bool gmap_1m_allowed(struct gmap *gmap, struct guest_fault *f, 637 + struct kvm_memory_slot *slot) 622 638 { 623 - return test_bit(GMAP_FLAG_ALLOW_HPAGE_1M, &gmap->flags); 639 + return test_bit(GMAP_FLAG_ALLOW_HPAGE_1M, &gmap->flags) && 640 + !((f->gfn ^ f->pfn) & ~_SEGMENT_FR_MASK) && 641 + slot->base_gfn <= ALIGN_DOWN(f->gfn, _PAGES_PER_SEGMENT) && 642 + slot->base_gfn + slot->npages >= ALIGN(f->gfn + 1, _PAGES_PER_SEGMENT); 624 643 } 625 644 626 - int gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, struct guest_fault *f) 645 + int gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, struct guest_fault *f, 646 + struct kvm_memory_slot *slot) 627 647 { 628 648 unsigned int order; 629 649 int rc, level; ··· 653 633 level = TABLE_TYPE_PAGE_TABLE; 654 634 if (f->page) { 655 635 order = folio_order(page_folio(f->page)); 656 - if (order >= get_order(_REGION3_SIZE) && gmap_2g_allowed(gmap, f->gfn)) 636 + if (order >= get_order(_REGION3_SIZE) && gmap_2g_allowed(gmap, f, slot)) 657 637 level = TABLE_TYPE_REGION3; 658 - else if (order >= get_order(_SEGMENT_SIZE) && gmap_1m_allowed(gmap, f->gfn)) 638 + else if (order >= get_order(_SEGMENT_SIZE) && gmap_1m_allowed(gmap, f, slot)) 659 639 level = TABLE_TYPE_SEGMENT; 660 640 } 661 641 rc = dat_link(mc, gmap->asce, level, uses_skeys(gmap), f);
+2 -1
arch/s390/kvm/gmap.h
··· 90 90 struct gmap *gmap_new_child(struct gmap *parent, gfn_t limit); 91 91 void gmap_remove_child(struct gmap *child); 92 92 void gmap_dispose(struct gmap *gmap); 93 - int gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, struct guest_fault *fault); 93 + int gmap_link(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, struct guest_fault *fault, 94 + struct kvm_memory_slot *slot); 94 95 void gmap_sync_dirty_log(struct gmap *gmap, gfn_t start, gfn_t end); 95 96 int gmap_set_limit(struct gmap *gmap, gfn_t limit); 96 97 int gmap_ucas_translate(struct kvm_s390_mmu_cache *mc, struct gmap *gmap, gpa_t *gaddr);