mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
vmalloc: add __GFP_SKIP_KASAN support
Patch series "kasan: hw_tags: Disable tagging for stack and page-tables", v4. Stacks and page tables are always accessed with the match-all tag, so assigning a new random tag every time at allocation and setting invalid tag at deallocation time, just adds overhead without improving the detection. With __GFP_SKIP_KASAN the page keeps its poison tag and KASAN_TAG_KERNEL (match-all tag) is stored in the page flags while keeping the poison tag in the hardware. The benefit of it is that 256 tag setting instruction per 4 kB page aren't needed at allocation and deallocation time. Thus match-all pointers still work, while non-match tags (other than poison tag) still fault. __GFP_SKIP_KASAN only skips for KASAN_HW_TAGS mode, so coverage is unchanged. Benchmark: The benchmark has two modes. In thread mode, the child process forks and creates N threads. In pgtable mode, the parent maps and faults a specified memory size and then forks repeatedly with children exiting immediately. Thread benchmark: 2000 iterations, 2000 threads: 2.575 s → 2.229 s (~13.4% faster) The pgtable samples: - 2048 MB, 2000 iters 19.08 s → 17.62 s (~7.6% faster) This patch (of 3): For allocations that will be accessed only with match-all pointers (e.g., kernel stacks), setting tags is wasted work. If the caller already set __GFP_SKIP_KASAN, skip tag setting of vmalloc pages. Before this patch, __GFP_SKIP_KASAN wasn't being used with vmalloc APIs. So it wasn't being checked. Now its being checked and acted upon. Other KASAN modes are unchanged because __GFP_SKIP_KASAN is ignored for them in the page allocator, and in vmalloc too we ignore this flag for them. This is a preparatory patch for optimizing kernel stack allocations. Link: https://lore.kernel.org/20260429102704.680174-1-dev.jain@arm.com Link: https://lore.kernel.org/20260429102704.680174-2-dev.jain@arm.com Signed-off-by: Muhammad Usama Anjum <usama.anjum@arm.com> Co-developed-by: Ryan Roberts <ryan.roberts@arm.com> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com> Co-developed-by: Dev Jain <dev.jain@arm.com> Signed-off-by: Dev Jain <dev.jain@arm.com> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Arnd Bergmann <arnd@arndb.de> Cc: Ben Segall <bsegall@google.com> Cc: David Hildenbrand <david@kernel.org> Cc: Dietmar Eggemann <dietmar.eggemann@arm.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Juri Lelli <juri.lelli@redhat.com> Cc: Kees Cook <kees@kernel.org> Cc: K Prateek Nayak <kprateek.nayak@amd.com> Cc: Liam Howlett <liam@infradead.org> Cc: Lorenzo Stoakes <ljs@kernel.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Cc: Mel Gorman <mgorman@suse.de> Cc: Michal Hocko <mhocko@suse.com> Cc: Mike Rapoport <rppt@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Suren Baghdasaryan <surenb@google.com> Cc: "Uladzislau Rezki (Sony)" <urezki@gmail.com> Cc: Valentin Schneider <vschneid@redhat.com> Cc: Vincent Guittot <vincent.guittot@linaro.org> Cc: Vlastimil Babka <vbabka@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
838376c60d
commit
b56ca146a2
|
|
@ -281,9 +281,9 @@ enum {
|
||||||
*
|
*
|
||||||
* %__GFP_SKIP_KASAN makes KASAN skip unpoisoning on page allocation.
|
* %__GFP_SKIP_KASAN makes KASAN skip unpoisoning on page allocation.
|
||||||
* Used for userspace and vmalloc pages; the latter are unpoisoned by
|
* Used for userspace and vmalloc pages; the latter are unpoisoned by
|
||||||
* kasan_unpoison_vmalloc instead. For userspace pages, results in
|
* kasan_unpoison_vmalloc instead. If passed to vmalloc, kasan_unpoison_vmalloc
|
||||||
* poisoning being skipped as well, see should_skip_kasan_poison for
|
* is skipped too. For userspace pages, results in poisoning being skipped as
|
||||||
* details. Only effective in HW_TAGS mode.
|
* well, see should_skip_kasan_poison for details. Only effective in HW_TAGS mode.
|
||||||
*/
|
*/
|
||||||
#define __GFP_NOWARN ((__force gfp_t)___GFP_NOWARN)
|
#define __GFP_NOWARN ((__force gfp_t)___GFP_NOWARN)
|
||||||
#define __GFP_COMP ((__force gfp_t)___GFP_COMP)
|
#define __GFP_COMP ((__force gfp_t)___GFP_COMP)
|
||||||
|
|
|
||||||
13
mm/vmalloc.c
13
mm/vmalloc.c
|
|
@ -3933,7 +3933,7 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
|
||||||
__GFP_NOFAIL | __GFP_ZERO |\
|
__GFP_NOFAIL | __GFP_ZERO |\
|
||||||
__GFP_NORETRY | __GFP_RETRY_MAYFAIL |\
|
__GFP_NORETRY | __GFP_RETRY_MAYFAIL |\
|
||||||
GFP_NOFS | GFP_NOIO | GFP_KERNEL_ACCOUNT |\
|
GFP_NOFS | GFP_NOIO | GFP_KERNEL_ACCOUNT |\
|
||||||
GFP_USER | __GFP_NOLOCKDEP)
|
GFP_USER | __GFP_NOLOCKDEP | __GFP_SKIP_KASAN)
|
||||||
|
|
||||||
static gfp_t vmalloc_fix_flags(gfp_t flags)
|
static gfp_t vmalloc_fix_flags(gfp_t flags)
|
||||||
{
|
{
|
||||||
|
|
@ -3974,6 +3974,9 @@ static gfp_t vmalloc_fix_flags(gfp_t flags)
|
||||||
*
|
*
|
||||||
* %__GFP_NOWARN can be used to suppress failure messages.
|
* %__GFP_NOWARN can be used to suppress failure messages.
|
||||||
*
|
*
|
||||||
|
* %__GFP_SKIP_KASAN can be used to skip unpoisoning of mapped pages
|
||||||
|
* (when prot=%PAGE_KERNEL).
|
||||||
|
*
|
||||||
* Can not be called from interrupt nor NMI contexts.
|
* Can not be called from interrupt nor NMI contexts.
|
||||||
* Return: the address of the area or %NULL on failure
|
* Return: the address of the area or %NULL on failure
|
||||||
*/
|
*/
|
||||||
|
|
@ -3987,6 +3990,7 @@ void *__vmalloc_node_range_noprof(unsigned long size, unsigned long align,
|
||||||
kasan_vmalloc_flags_t kasan_flags = KASAN_VMALLOC_NONE;
|
kasan_vmalloc_flags_t kasan_flags = KASAN_VMALLOC_NONE;
|
||||||
unsigned long original_align = align;
|
unsigned long original_align = align;
|
||||||
unsigned int shift = PAGE_SHIFT;
|
unsigned int shift = PAGE_SHIFT;
|
||||||
|
bool skip_vmalloc_kasan = kasan_hw_tags_enabled() && (gfp_mask & __GFP_SKIP_KASAN);
|
||||||
|
|
||||||
if (WARN_ON_ONCE(!size))
|
if (WARN_ON_ONCE(!size))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -4017,7 +4021,7 @@ void *__vmalloc_node_range_noprof(unsigned long size, unsigned long align,
|
||||||
again:
|
again:
|
||||||
area = __get_vm_area_node(size, align, shift, VM_ALLOC |
|
area = __get_vm_area_node(size, align, shift, VM_ALLOC |
|
||||||
VM_UNINITIALIZED | vm_flags, start, end, node,
|
VM_UNINITIALIZED | vm_flags, start, end, node,
|
||||||
gfp_mask, caller);
|
gfp_mask & ~__GFP_SKIP_KASAN, caller);
|
||||||
if (!area) {
|
if (!area) {
|
||||||
bool nofail = gfp_mask & __GFP_NOFAIL;
|
bool nofail = gfp_mask & __GFP_NOFAIL;
|
||||||
warn_alloc(gfp_mask, NULL,
|
warn_alloc(gfp_mask, NULL,
|
||||||
|
|
@ -4035,7 +4039,7 @@ void *__vmalloc_node_range_noprof(unsigned long size, unsigned long align,
|
||||||
* kasan_unpoison_vmalloc().
|
* kasan_unpoison_vmalloc().
|
||||||
*/
|
*/
|
||||||
if (pgprot_val(prot) == pgprot_val(PAGE_KERNEL)) {
|
if (pgprot_val(prot) == pgprot_val(PAGE_KERNEL)) {
|
||||||
if (kasan_hw_tags_enabled()) {
|
if (kasan_hw_tags_enabled() && !skip_vmalloc_kasan) {
|
||||||
/*
|
/*
|
||||||
* Modify protection bits to allow tagging.
|
* Modify protection bits to allow tagging.
|
||||||
* This must be done before mapping.
|
* This must be done before mapping.
|
||||||
|
|
@ -4072,7 +4076,8 @@ void *__vmalloc_node_range_noprof(unsigned long size, unsigned long align,
|
||||||
(gfp_mask & __GFP_SKIP_ZERO))
|
(gfp_mask & __GFP_SKIP_ZERO))
|
||||||
kasan_flags |= KASAN_VMALLOC_INIT;
|
kasan_flags |= KASAN_VMALLOC_INIT;
|
||||||
/* KASAN_VMALLOC_PROT_NORMAL already set if required. */
|
/* KASAN_VMALLOC_PROT_NORMAL already set if required. */
|
||||||
area->addr = kasan_unpoison_vmalloc(area->addr, size, kasan_flags);
|
if (!skip_vmalloc_kasan)
|
||||||
|
area->addr = kasan_unpoison_vmalloc(area->addr, size, kasan_flags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In this function, newly allocated vm_struct has VM_UNINITIALIZED
|
* In this function, newly allocated vm_struct has VM_UNINITIALIZED
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user