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: Oscar 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: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
Oscar Salvador 2024-10-07 09:50:32 +02:00 committed by Andrew Morton
parent 1317a5e7f7
commit a8d457b29b
2 changed files with 42 additions and 12 deletions

View File

@ -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;
info.align_mask = (flags & MAP_SHARED) ?
(PAGE_MASK & (SHMLBA - 1)) : 0;
info.align_offset = pgoff << PAGE_SHIFT;
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);
}

View File

@ -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,8 +144,9 @@ 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_offset = pgoff << PAGE_SHIFT;
info.align_mask = get_align_mask(filp, flags);
if (!file_hugepage)
info.align_offset = pgoff << PAGE_SHIFT;
addr = vm_unmapped_area(&info);
if ((addr & ~PAGE_MASK) && task_size > VA_EXCLUDE_END) {
@ -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,8 +212,9 @@ 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_offset = pgoff << PAGE_SHIFT;
info.align_mask = get_align_mask(filp, flags);
if (!file_hugepage)
info.align_offset = pgoff << PAGE_SHIFT;
addr = vm_unmapped_area(&info);
/*