@@ -147,8 +147,20 @@ static inline bool transhuge_vma_enabled(struct vm_area_struct *vma,
#define hugetext_enabled() \
(transparent_hugepage_flags & \
(1<<TRANSPARENT_HUGEPAGE_HUGETEXT_ENABLED_FLAG))
+
+extern unsigned long hugetext_get_unmapped_area(struct file *filp,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags);
#else
#define hugetext_enabled() false
+
+static inline unsigned long hugetext_get_unmapped_area(struct file *filp,
+ unsigned long addr, unsigned long len, unsigned long pgoff,
+ unsigned long flags)
+{
+ BUILD_BUG();
+ return 0;
+}
#endif /* CONFIG_HUGETEXT */
static inline bool vma_is_hugetext(struct vm_area_struct *vma,
@@ -650,6 +650,21 @@ unsigned long thp_get_unmapped_area(struct file *filp, unsigned long addr,
}
EXPORT_SYMBOL_GPL(thp_get_unmapped_area);
+#ifdef CONFIG_HUGETEXT
+unsigned long hugetext_get_unmapped_area(struct file *filp, unsigned long addr,
+ unsigned long len, unsigned long pgoff, unsigned long flags)
+{
+ unsigned long ret;
+ loff_t off = (loff_t)pgoff << PAGE_SHIFT;
+
+ ret = __thp_get_unmapped_area(filp, addr, len, off, flags, PMD_SIZE);
+ if (ret)
+ return ret;
+
+ return current->mm->get_unmapped_area(filp, addr, len, pgoff, flags);
+}
+#endif /* CONFIG_HUGETEXT */
+
static vm_fault_t __do_huge_pmd_anonymous_page(struct vm_fault *vmf,
struct page *page, gfp_t gfp)
{
@@ -2242,8 +2242,26 @@ get_unmapped_area(struct file *file, unsigned long addr, unsigned long len,
get_area = current->mm->get_unmapped_area;
if (file) {
+#ifdef CONFIG_HUGETEXT
+ /*
+ * Prior to the file->f_op->get_unmapped_area.
+ *
+ * If hugetext is enabled, except for MAP_FIXED, it always
+ * make the mapping address of files that have executable
+ * attribute be mapped in 2MB alignment.
+ */
+ struct inode *inode = file_inode(file);
+
+ if (hugetext_enabled() && (inode->i_mode & 0111) &&
+ (!file->f_op->get_unmapped_area ||
+ file->f_op->get_unmapped_area == thp_get_unmapped_area))
+ get_area = hugetext_get_unmapped_area;
+ else if (file->f_op->get_unmapped_area)
+ get_area = file->f_op->get_unmapped_area;
+#else
if (file->f_op->get_unmapped_area)
get_area = file->f_op->get_unmapped_area;
+#endif
} else if (flags & MAP_SHARED) {
/*
* mmap_region() will call shmem_zero_setup() to create a file,