static int mapping_level(struct kvm_vcpu *vcpu, gfn_t large_gfn,
int *max_levelp)
{
- int host_level, max_level = *max_levelp;
+ int max_level = *max_levelp;
struct kvm_memory_slot *slot;
if (unlikely(max_level == PT_PAGE_TABLE_LEVEL))
return PT_PAGE_TABLE_LEVEL;
}
- host_level = host_mapping_level(vcpu->kvm, large_gfn);
-
- if (host_level == PT_PAGE_TABLE_LEVEL)
- return host_level;
-
- max_level = min(kvm_x86_ops->get_lpage_level(), host_level);
+ max_level = min(max_level, kvm_x86_ops->get_lpage_level());
for ( ; max_level > PT_PAGE_TABLE_LEVEL; max_level--) {
if (!__mmu_gfn_lpage_is_disallowed(large_gfn, max_level, slot))
break;
}
- return max_level;
+ *max_levelp = max_level;
+
+ if (max_level == PT_PAGE_TABLE_LEVEL)
+ return PT_PAGE_TABLE_LEVEL;
+
+ /*
+ * Note, host_mapping_level() does *not* handle transparent huge pages.
+ * As suggested by "mapping", it reflects the page size established by
+ * the associated vma, if there is one, i.e. host_mapping_level() will
+ * return a huge page level if and only if a vma exists and the backing
+ * implementation for the vma uses huge pages, e.g. hugetlbfs and dax.
+ * So, do not propagate host_mapping_level() to max_level as KVM can
+ * still promote the guest mapping to a huge page in the THP case.
+ */
+ return host_mapping_level(vcpu->kvm, large_gfn);
}
/*
*/
if (!is_error_noslot_pfn(pfn) && !kvm_is_reserved_pfn(pfn) &&
!kvm_is_zone_device_pfn(pfn) && level == PT_PAGE_TABLE_LEVEL &&
- PageTransCompoundMap(pfn_to_page(pfn)) &&
- !mmu_gfn_lpage_is_disallowed(vcpu, gfn, PT_DIRECTORY_LEVEL)) {
+ PageTransCompoundMap(pfn_to_page(pfn))) {
unsigned long mask;
/*
* mmu_notifier_retry was successful and we hold the