From: Zhou Guanghui <zhouguanghui1@huawei.com> hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I7SZC2 ----------------------------------------------------------------- A range is reserved from the user address space to ensure that the process cannot apply for the address range. Signed-off-by: Zhou Guanghui <zhouguanghui1@huawei.com> --- fs/hugetlbfs/inode.c | 13 +++++ include/linux/ascend_vm.h | 69 ++++++++++++++++++++++++++ include/linux/share_pool.h | 11 ++-- include/uapi/asm-generic/mman-common.h | 1 + mm/Makefile | 1 + mm/ascend_vm.c | 21 ++++++++ mm/mmap.c | 15 ++++-- 7 files changed, 125 insertions(+), 6 deletions(-) create mode 100644 include/linux/ascend_vm.h create mode 100644 mm/ascend_vm.c diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index c4f3c5d631f8..ebe4e0f60441 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -36,6 +36,7 @@ #include <linux/migrate.h> #include <linux/uio.h> #include <linux/dynamic_pool.h> +#include <linux/ascend_vm.h> #include <linux/uaccess.h> #include <linux/sched/mm.h> @@ -208,6 +209,9 @@ hugetlb_get_unmapped_area_bottomup(struct file *file, unsigned long addr, info.high_limit = arch_get_mmap_end(addr, len, flags); info.align_mask = PAGE_MASK & ~huge_page_mask(h); info.align_offset = 0; + + ascend_mmap_get_area(&info, flags); + return vm_unmapped_area(&info); } @@ -224,6 +228,9 @@ hugetlb_get_unmapped_area_topdown(struct file *file, unsigned long addr, info.high_limit = arch_get_mmap_base(addr, current->mm->mmap_base); info.align_mask = PAGE_MASK & ~huge_page_mask(h); info.align_offset = 0; + + ascend_mmap_get_area(&info, flags); + addr = vm_unmapped_area(&info); /* @@ -237,6 +244,9 @@ hugetlb_get_unmapped_area_topdown(struct file *file, unsigned long addr, info.flags = 0; info.low_limit = current->mm->mmap_base; info.high_limit = arch_get_mmap_end(addr, len, flags); + + ascend_mmap_get_area(&info, flags); + addr = vm_unmapped_area(&info); } @@ -258,6 +268,9 @@ generic_hugetlb_get_unmapped_area(struct file *file, unsigned long addr, if (len > TASK_SIZE) return -ENOMEM; + if (ascend_mmap_check_addr(addr, len, flags)) + return -EINVAL; + if (flags & MAP_FIXED) { if (prepare_hugepage_range(file, addr, len)) return -EINVAL; diff --git a/include/linux/ascend_vm.h b/include/linux/ascend_vm.h new file mode 100644 index 000000000000..f099d933333f --- /dev/null +++ b/include/linux/ascend_vm.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __ASCEND_VM__ +#define __ASCEND_VM__ + +#include <uapi/linux/mman.h> +#include <linux/share_pool.h> + +#ifdef CONFIG_SVSP +extern struct static_key_false enable_mmap_svsp; + +/* skip 7T for stack */ +#define MMAP_SVSP_SKIP 0x070000000000UL +/* reserve 1T size*/ +#define SVSP_MMAP_SIZE 0x010000000000UL +#define SVSP_MMAP_END (TASK_SIZE - MMAP_SVSP_SKIP) +#define SVSP_MMAP_BASE (SVSP_MMAP_END - SVSP_MMAP_SIZE) + +static inline int svsp_mmap_check(unsigned long addr, unsigned long len) +{ + /* svsp does not support fix addr, so we do not check flag here */ + if (static_branch_likely(&enable_mmap_svsp) && + addr + len > SVSP_MMAP_BASE && addr < SVSP_MMAP_END) + return -EINVAL; + else + return 0; +} + +static inline void svsp_mmap_get_area(struct vm_unmapped_area_info *info, + unsigned long flags) +{ + if (static_branch_likely(&enable_mmap_svsp) && (flags & MAP_SVSP)) { + info->low_limit = SVSP_MMAP_BASE; + info->high_limit = SVSP_MMAP_END; + } else { + info->high_limit = min(info->high_limit, SVSP_MMAP_BASE); + } +} + +#else /* CONFIG_SVSP */ +static inline int svsp_mmap_check(unsigned long addr, unsigned long len) +{ + return 0; +} + +static inline void svsp_mmap_get_area(struct vm_unmapped_area_info *info, + unsigned long flags) +{ } +#endif /* CONFIG_SVSP */ + +static inline void ascend_mmap_get_area(struct vm_unmapped_area_info *info, + unsigned long flags) +{ + svsp_mmap_get_area(info, flags); + sp_area_work_around(info, flags); +} + +static inline int ascend_mmap_check_addr(unsigned long addr, unsigned long len, + unsigned long flags) +{ + if (sp_check_mmap_addr(addr, flags)) + return -EINVAL; + + if (svsp_mmap_check(addr, len)) + return -EINVAL; + + return 0; +} + +#endif /* __ASCEND_VM__ */ diff --git a/include/linux/share_pool.h b/include/linux/share_pool.h index f177a9e9d204..2db4689616e4 100644 --- a/include/linux/share_pool.h +++ b/include/linux/share_pool.h @@ -131,9 +131,13 @@ static inline void sp_mm_clean(struct mm_struct *mm) __sp_mm_clean(mm); } -static inline void sp_area_work_around(struct vm_unmapped_area_info *info) +static inline void sp_area_work_around(struct vm_unmapped_area_info *info, + unsigned long flags) { - if (sp_is_enabled()) + /* the MAP_SVSP couldn't work with MAP_SHARE_POOL. In addition, the + * address ranges corresponding to the two flags must not overlap. + */ + if (sp_is_enabled() && !(flags & MAP_SVSP)) info->high_limit = min(info->high_limit, MMAP_SHARE_POOL_START); } @@ -244,7 +248,8 @@ static inline bool sp_is_enabled(void) return false; } -static inline void sp_area_work_around(struct vm_unmapped_area_info *info) +static inline void sp_area_work_around(struct vm_unmapped_area_info *info, + unsigned long flags) { } diff --git a/include/uapi/asm-generic/mman-common.h b/include/uapi/asm-generic/mman-common.h index 14e5498efd7a..096c9018d2d5 100644 --- a/include/uapi/asm-generic/mman-common.h +++ b/include/uapi/asm-generic/mman-common.h @@ -30,6 +30,7 @@ #define MAP_SYNC 0x080000 /* perform synchronous page faults for the mapping */ #define MAP_FIXED_NOREPLACE 0x100000 /* MAP_FIXED which doesn't unmap underlying mapping */ +#define MAP_SVSP 0x400000 #define MAP_UNINITIALIZED 0x4000000 /* For anonymous mmap, memory could be * uninitialized */ diff --git a/mm/Makefile b/mm/Makefile index 08be0241b94b..cd0df6e57417 100644 --- a/mm/Makefile +++ b/mm/Makefile @@ -141,6 +141,7 @@ obj-$(CONFIG_HAVE_BOOTMEM_INFO_NODE) += bootmem_info.o obj-$(CONFIG_GENERIC_IOREMAP) += ioremap.o obj-$(CONFIG_SHRINKER_DEBUG) += shrinker_debug.o obj-$(CONFIG_SHARE_POOL) += share_pool.o +obj-$(CONFIG_ASCEND_FEATURES) += ascend_vm.o obj-$(CONFIG_MEMCG_MEMFS_INFO) += memcg_memfs_info.o obj-$(CONFIG_ETMEM) += etmem.o obj-$(CONFIG_PAGE_CACHE_LIMIT) += page_cache_limit.o diff --git a/mm/ascend_vm.c b/mm/ascend_vm.c new file mode 100644 index 000000000000..84c3612fb9ca --- /dev/null +++ b/mm/ascend_vm.c @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0 +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/mm_inline.h> +#include <linux/ascend_vm.h> + +#ifdef CONFIG_SVSP + +DEFINE_STATIC_KEY_FALSE(enable_mmap_svsp); + +static int __init ascend_enable_mmap_svsp(char *s) +{ + static_branch_enable(&enable_mmap_svsp); + + pr_info("Ascend enable svsp mmap features\n"); + + return 1; +} +__setup("enable_mmap_svsp", ascend_enable_mmap_svsp); + +#endif diff --git a/mm/mmap.c b/mm/mmap.c index 8b1a182eebb7..f0baaec7e3ad 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -48,6 +48,7 @@ #include <linux/sched/mm.h> #include <linux/ksm.h> #include <linux/share_pool.h> +#include <linux/ascend_vm.h> #include <linux/uaccess.h> #include <asm/cacheflush.h> @@ -1697,7 +1698,6 @@ unsigned long vm_unmapped_area(struct vm_unmapped_area_info *info) { unsigned long addr; - sp_area_work_around(info); if (info->flags & VM_UNMAPPED_AREA_TOPDOWN) addr = unmapped_area_topdown(info); else @@ -1731,7 +1731,7 @@ generic_get_unmapped_area(struct file *filp, unsigned long addr, if (len > mmap_end - mmap_min_addr) return -ENOMEM; - if (sp_check_mmap_addr(addr, flags)) + if (ascend_mmap_check_addr(addr, len, flags)) return -EINVAL; if (flags & MAP_FIXED) @@ -1752,6 +1752,9 @@ generic_get_unmapped_area(struct file *filp, unsigned long addr, info.high_limit = mmap_end; info.align_mask = 0; info.align_offset = 0; + + ascend_mmap_get_area(&info, flags); + return vm_unmapped_area(&info); } @@ -1783,7 +1786,7 @@ generic_get_unmapped_area_topdown(struct file *filp, unsigned long addr, if (len > mmap_end - mmap_min_addr) return -ENOMEM; - if (sp_check_mmap_addr(addr, flags)) + if (ascend_mmap_check_addr(addr, len, flags)) return -EINVAL; if (flags & MAP_FIXED) @@ -1805,6 +1808,9 @@ generic_get_unmapped_area_topdown(struct file *filp, unsigned long addr, info.high_limit = arch_get_mmap_base(addr, mm->mmap_base); info.align_mask = 0; info.align_offset = 0; + + ascend_mmap_get_area(&info, flags); + addr = vm_unmapped_area(&info); /* @@ -1818,6 +1824,9 @@ generic_get_unmapped_area_topdown(struct file *filp, unsigned long addr, info.flags = 0; info.low_limit = TASK_UNMAPPED_BASE; info.high_limit = mmap_end; + + ascend_mmap_get_area(&info, flags); + addr = vm_unmapped_area(&info); } -- 2.43.0