Commit a8d457b2 authored by Oscar Salvador's avatar Oscar Salvador Committed by Andrew Morton
Browse files

arch/sparc: teach arch_get_unmapped_area{_topdown} to handle hugetlb mappings

We want to stop special casing hugetlb mappings and make them go through
generic channels, so teach arch_get_unmapped_area{_topdown} to handle
those.

sparc specific hugetlb function does not set info.align_offset, and does
not care about adjusting the align_mask for MAP_SHARED cases, so the same
here for compatibility.

Link: https://lkml.kernel.org/r/20241007075037.267650-5-osalvador@suse.de


Signed-off-by: default avatarOscar Salvador <osalvador@suse.de>
Cc: David Hildenbrand <david@redhat.com>
Cc: Donet Tom <donettom@linux.ibm.com>
Cc: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Muchun Song <muchun.song@linux.dev>
Cc: Peter Xu <peterx@redhat.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 1317a5e7
Loading
Loading
Loading
Loading
+13 −4
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@
#include <linux/utsname.h>
#include <linux/smp.h>
#include <linux/ipc.h>
#include <linux/hugetlb.h>

#include <linux/uaccess.h>
#include <asm/unistd.h>
@@ -42,12 +43,16 @@ SYSCALL_DEFINE0(getpagesize)
unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags, vm_flags_t vm_flags)
{
	struct vm_unmapped_area_info info = {};
	bool file_hugepage = false;

	if (filp && is_file_hugepages(filp))
		file_hugepage = true;

	if (flags & MAP_FIXED) {
		/* We do not accept a shared mapping if it would violate
		 * cache aliasing constraints.
		 */
		if ((flags & MAP_SHARED) &&
		if (!file_hugepage && (flags & MAP_SHARED) &&
		    ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)))
			return -EINVAL;
		return addr;
@@ -62,9 +67,13 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
	info.length = len;
	info.low_limit = addr;
	info.high_limit = TASK_SIZE;
	if (!file_hugepage) {
		info.align_mask = (flags & MAP_SHARED) ?
			(PAGE_MASK & (SHMLBA - 1)) : 0;
		info.align_offset = pgoff << PAGE_SHIFT;
	} else {
		info.align_mask = huge_page_mask_align(filp);
	}
	return vm_unmapped_area(&info);
}

+29 −8
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <linux/context_tracking.h>
#include <linux/timex.h>
#include <linux/uaccess.h>
#include <linux/hugetlb.h>

#include <asm/utrap.h>
#include <asm/unistd.h>
@@ -87,6 +88,16 @@ static inline unsigned long COLOR_ALIGN(unsigned long addr,
	return base + off;
}

static unsigned long get_align_mask(struct file *filp, unsigned long flags)
{
	if (filp && is_file_hugepages(filp))
		return huge_page_mask_align(filp);
	if (filp || (flags & MAP_SHARED))
		return PAGE_MASK & (SHMLBA - 1);

	return 0;
}

unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags, vm_flags_t vm_flags)
{
	struct mm_struct *mm = current->mm;
@@ -94,12 +105,16 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
	unsigned long task_size = TASK_SIZE;
	int do_color_align;
	struct vm_unmapped_area_info info = {};
	bool file_hugepage = false;

	if (filp && is_file_hugepages(filp))
		file_hugepage = true;

	if (flags & MAP_FIXED) {
		/* We do not accept a shared mapping if it would violate
		 * cache aliasing constraints.
		 */
		if ((flags & MAP_SHARED) &&
		if (!file_hugepage && (flags & MAP_SHARED) &&
		    ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)))
			return -EINVAL;
		return addr;
@@ -111,7 +126,7 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
		return -ENOMEM;

	do_color_align = 0;
	if (filp || (flags & MAP_SHARED))
	if ((filp || (flags & MAP_SHARED)) && !file_hugepage)
		do_color_align = 1;

	if (addr) {
@@ -129,7 +144,8 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr, unsi
	info.length = len;
	info.low_limit = TASK_UNMAPPED_BASE;
	info.high_limit = min(task_size, VA_EXCLUDE_START);
	info.align_mask = do_color_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
	info.align_mask = get_align_mask(filp, flags);
	if (!file_hugepage)
		info.align_offset = pgoff << PAGE_SHIFT;
	addr = vm_unmapped_area(&info);

@@ -154,15 +170,19 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
	unsigned long addr = addr0;
	int do_color_align;
	struct vm_unmapped_area_info info = {};
	bool file_hugepage = false;

	/* This should only ever run for 32-bit processes.  */
	BUG_ON(!test_thread_flag(TIF_32BIT));

	if (filp && is_file_hugepages(filp))
		file_hugepage = true;

	if (flags & MAP_FIXED) {
		/* We do not accept a shared mapping if it would violate
		 * cache aliasing constraints.
		 */
		if ((flags & MAP_SHARED) &&
		if (!file_hugepage && (flags & MAP_SHARED) &&
		    ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1)))
			return -EINVAL;
		return addr;
@@ -172,7 +192,7 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
		return -ENOMEM;

	do_color_align = 0;
	if (filp || (flags & MAP_SHARED))
	if ((filp || (flags & MAP_SHARED)) && !file_hugepage)
		do_color_align = 1;

	/* requesting a specific address */
@@ -192,7 +212,8 @@ arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0,
	info.length = len;
	info.low_limit = PAGE_SIZE;
	info.high_limit = mm->mmap_base;
	info.align_mask = do_color_align ? (PAGE_MASK & (SHMLBA - 1)) : 0;
	info.align_mask = get_align_mask(filp, flags);
	if (!file_hugepage)
		info.align_offset = pgoff << PAGE_SHIFT;
	addr = vm_unmapped_area(&info);