mirror of https://github.com/torvalds/linux.git
kmsan: remove hard-coded GFP_KERNEL flags
kmsan_vmap_pages_range_noflush() allocates its temp s_pages/o_pages arrays with GFP_KERNEL, which may sleep. This is inconsistent with vmalloc() as it will support non-blocking requests later. Plumb gfp_mask through the kmsan_vmap_pages_range_noflush(), so it can use it internally for its demand. Please note, the subsequent __vmap_pages_range_noflush() still uses GFP_KERNEL and can sleep. If a caller runs under reclaim constraints, sleeping is forbidden, it must establish the appropriate memalloc scope API. Link: https://lkml.kernel.org/r/20251007122035.56347-8-urezki@gmail.com Signed-off-by: Uladzislau Rezki (Sony) <urezki@gmail.com> Reviewed-by: Alexander Potapenko <glider@google.com> Cc: Marco Elver <elver@google.com> Cc: Andrey Ryabinin <ryabinin.a.a@gmail.com> Cc: Baoquan He <bhe@redhat.com> Cc: Michal Hocko <mhocko@kernel.org> Cc: Michal Hocko <mhocko@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
ad435e79f8
commit
b186a94227
|
|
@ -133,6 +133,7 @@ void kmsan_kfree_large(const void *ptr);
|
||||||
* @prot: page protection flags used for vmap.
|
* @prot: page protection flags used for vmap.
|
||||||
* @pages: array of pages.
|
* @pages: array of pages.
|
||||||
* @page_shift: page_shift passed to vmap_range_noflush().
|
* @page_shift: page_shift passed to vmap_range_noflush().
|
||||||
|
* @gfp_mask: gfp_mask to use internally.
|
||||||
*
|
*
|
||||||
* KMSAN maps shadow and origin pages of @pages into contiguous ranges in
|
* KMSAN maps shadow and origin pages of @pages into contiguous ranges in
|
||||||
* vmalloc metadata address range. Returns 0 on success, callers must check
|
* vmalloc metadata address range. Returns 0 on success, callers must check
|
||||||
|
|
@ -142,7 +143,8 @@ int __must_check kmsan_vmap_pages_range_noflush(unsigned long start,
|
||||||
unsigned long end,
|
unsigned long end,
|
||||||
pgprot_t prot,
|
pgprot_t prot,
|
||||||
struct page **pages,
|
struct page **pages,
|
||||||
unsigned int page_shift);
|
unsigned int page_shift,
|
||||||
|
gfp_t gfp_mask);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* kmsan_vunmap_kernel_range_noflush() - Notify KMSAN about a vunmap.
|
* kmsan_vunmap_kernel_range_noflush() - Notify KMSAN about a vunmap.
|
||||||
|
|
@ -347,7 +349,7 @@ static inline void kmsan_kfree_large(const void *ptr)
|
||||||
|
|
||||||
static inline int __must_check kmsan_vmap_pages_range_noflush(
|
static inline int __must_check kmsan_vmap_pages_range_noflush(
|
||||||
unsigned long start, unsigned long end, pgprot_t prot,
|
unsigned long start, unsigned long end, pgprot_t prot,
|
||||||
struct page **pages, unsigned int page_shift)
|
struct page **pages, unsigned int page_shift, gfp_t gfp_mask)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1355,7 +1355,7 @@ size_t splice_folio_into_pipe(struct pipe_inode_info *pipe,
|
||||||
#ifdef CONFIG_MMU
|
#ifdef CONFIG_MMU
|
||||||
void __init vmalloc_init(void);
|
void __init vmalloc_init(void);
|
||||||
int __must_check vmap_pages_range_noflush(unsigned long addr, unsigned long end,
|
int __must_check vmap_pages_range_noflush(unsigned long addr, unsigned long end,
|
||||||
pgprot_t prot, struct page **pages, unsigned int page_shift);
|
pgprot_t prot, struct page **pages, unsigned int page_shift, gfp_t gfp_mask);
|
||||||
unsigned int get_vm_area_page_order(struct vm_struct *vm);
|
unsigned int get_vm_area_page_order(struct vm_struct *vm);
|
||||||
#else
|
#else
|
||||||
static inline void vmalloc_init(void)
|
static inline void vmalloc_init(void)
|
||||||
|
|
@ -1364,7 +1364,7 @@ static inline void vmalloc_init(void)
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
int __must_check vmap_pages_range_noflush(unsigned long addr, unsigned long end,
|
int __must_check vmap_pages_range_noflush(unsigned long addr, unsigned long end,
|
||||||
pgprot_t prot, struct page **pages, unsigned int page_shift)
|
pgprot_t prot, struct page **pages, unsigned int page_shift, gfp_t gfp_mask)
|
||||||
{
|
{
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -215,7 +215,7 @@ void kmsan_free_page(struct page *page, unsigned int order)
|
||||||
|
|
||||||
int kmsan_vmap_pages_range_noflush(unsigned long start, unsigned long end,
|
int kmsan_vmap_pages_range_noflush(unsigned long start, unsigned long end,
|
||||||
pgprot_t prot, struct page **pages,
|
pgprot_t prot, struct page **pages,
|
||||||
unsigned int page_shift)
|
unsigned int page_shift, gfp_t gfp_mask)
|
||||||
{
|
{
|
||||||
unsigned long shadow_start, origin_start, shadow_end, origin_end;
|
unsigned long shadow_start, origin_start, shadow_end, origin_end;
|
||||||
struct page **s_pages, **o_pages;
|
struct page **s_pages, **o_pages;
|
||||||
|
|
@ -230,8 +230,8 @@ int kmsan_vmap_pages_range_noflush(unsigned long start, unsigned long end,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
nr = (end - start) / PAGE_SIZE;
|
nr = (end - start) / PAGE_SIZE;
|
||||||
s_pages = kcalloc(nr, sizeof(*s_pages), GFP_KERNEL);
|
s_pages = kcalloc(nr, sizeof(*s_pages), gfp_mask);
|
||||||
o_pages = kcalloc(nr, sizeof(*o_pages), GFP_KERNEL);
|
o_pages = kcalloc(nr, sizeof(*o_pages), gfp_mask);
|
||||||
if (!s_pages || !o_pages) {
|
if (!s_pages || !o_pages) {
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto ret;
|
goto ret;
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,7 @@ static int __pcpu_map_pages(unsigned long addr, struct page **pages,
|
||||||
int nr_pages)
|
int nr_pages)
|
||||||
{
|
{
|
||||||
return vmap_pages_range_noflush(addr, addr + (nr_pages << PAGE_SHIFT),
|
return vmap_pages_range_noflush(addr, addr + (nr_pages << PAGE_SHIFT),
|
||||||
PAGE_KERNEL, pages, PAGE_SHIFT);
|
PAGE_KERNEL, pages, PAGE_SHIFT, GFP_KERNEL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
26
mm/vmalloc.c
26
mm/vmalloc.c
|
|
@ -671,16 +671,28 @@ int __vmap_pages_range_noflush(unsigned long addr, unsigned long end,
|
||||||
}
|
}
|
||||||
|
|
||||||
int vmap_pages_range_noflush(unsigned long addr, unsigned long end,
|
int vmap_pages_range_noflush(unsigned long addr, unsigned long end,
|
||||||
pgprot_t prot, struct page **pages, unsigned int page_shift)
|
pgprot_t prot, struct page **pages, unsigned int page_shift,
|
||||||
|
gfp_t gfp_mask)
|
||||||
{
|
{
|
||||||
int ret = kmsan_vmap_pages_range_noflush(addr, end, prot, pages,
|
int ret = kmsan_vmap_pages_range_noflush(addr, end, prot, pages,
|
||||||
page_shift);
|
page_shift, gfp_mask);
|
||||||
|
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
return __vmap_pages_range_noflush(addr, end, prot, pages, page_shift);
|
return __vmap_pages_range_noflush(addr, end, prot, pages, page_shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __vmap_pages_range(unsigned long addr, unsigned long end,
|
||||||
|
pgprot_t prot, struct page **pages, unsigned int page_shift,
|
||||||
|
gfp_t gfp_mask)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = vmap_pages_range_noflush(addr, end, prot, pages, page_shift, gfp_mask);
|
||||||
|
flush_cache_vmap(addr, end);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vmap_pages_range - map pages to a kernel virtual address
|
* vmap_pages_range - map pages to a kernel virtual address
|
||||||
* @addr: start of the VM area to map
|
* @addr: start of the VM area to map
|
||||||
|
|
@ -696,11 +708,7 @@ int vmap_pages_range_noflush(unsigned long addr, unsigned long end,
|
||||||
int vmap_pages_range(unsigned long addr, unsigned long end,
|
int vmap_pages_range(unsigned long addr, unsigned long end,
|
||||||
pgprot_t prot, struct page **pages, unsigned int page_shift)
|
pgprot_t prot, struct page **pages, unsigned int page_shift)
|
||||||
{
|
{
|
||||||
int err;
|
return __vmap_pages_range(addr, end, prot, pages, page_shift, GFP_KERNEL);
|
||||||
|
|
||||||
err = vmap_pages_range_noflush(addr, end, prot, pages, page_shift);
|
|
||||||
flush_cache_vmap(addr, end);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_sparse_vm_area(struct vm_struct *area, unsigned long start,
|
static int check_sparse_vm_area(struct vm_struct *area, unsigned long start,
|
||||||
|
|
@ -3839,8 +3847,8 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
|
||||||
*/
|
*/
|
||||||
flags = memalloc_apply_gfp_scope(gfp_mask);
|
flags = memalloc_apply_gfp_scope(gfp_mask);
|
||||||
do {
|
do {
|
||||||
ret = vmap_pages_range(addr, addr + size, prot, area->pages,
|
ret = __vmap_pages_range(addr, addr + size, prot, area->pages,
|
||||||
page_shift);
|
page_shift, nested_gfp);
|
||||||
if (nofail && (ret < 0))
|
if (nofail && (ret < 0))
|
||||||
schedule_timeout_uninterruptible(1);
|
schedule_timeout_uninterruptible(1);
|
||||||
} while (nofail && (ret < 0));
|
} while (nofail && (ret < 0));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue