Re: [RFC PATCH v2] mm/vmalloc: fix incorrect __vmap_pages_range_noflush() if vm_area_alloc_pages() from high order fallback to order0

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jul 26, 2024 at 4:40 AM Hailong Liu <hailong.liu@xxxxxxxx> wrote:
>
> On Thu, 25. Jul 19:39, Baoquan He wrote:
> > On 07/25/24 at 11:53am, hailong.liu@xxxxxxxx wrote:
> > > From: "Hailong.Liu" <hailong.liu@xxxxxxxx>
> > >
> > > The scenario where the issue occurs is as follows:
> > > CONFIG: vmap_allow_huge = true && 2M is for PMD_SIZE
> > > kvmalloc(2M, __GFP_NOFAIL|GFP_XXX)
> > >     __vmalloc_node_range(vm_flags=VM_ALLOW_HUGE_VMAP)
> > >         vm_area_alloc_pages(order=9) --->allocs order9 failed and fallback to order0
> > >                                         and phys_addr is aligned with PMD_SIZE
> > >             vmap_pages_range
> > >                 vmap_pages_range_noflush
> > >                     __vmap_pages_range_noflush(page_shift = 21) ----> incorrect vmap *huge* here
> > >
> > > In fact, as long as page_shift is not equal to PAGE_SHIFT, there
> > > might be issues with the __vmap_pages_range_noflush().
> > >
> > > The patch also remove VM_ALLOW_HUGE_VMAP in kvmalloc_node(), There
> > > are several reasons for this:
> > > - This increases memory footprint because ALIGNMENT.
> > > - This increases the likelihood of kvmalloc allocation failures.
> > > - Without this it fixes the origin issue of kvmalloc with __GFP_NOFAIL may return NULL.
> > > Besides if drivers want to vmap huge, user vmalloc_huge instead.
> >
> > Seem there are two issues you are folding into one patch:
> Got it. I will separate in the next version.
>
> >
> > one is the wrong informatin passed into __vmap_pages_range_noflush();
> > the other is you want to take off VM_ALLOW_HUGE_VMAP on kvmalloc().
> >
> > About the 1st one, do you think below draft is OK to you?
> >
> > Pass out the fall back order and adjust the order and shift for later
> > usage, mainly for vmap_pages_range().
> >
> > diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> > index 260897b21b11..5ee9ae518f3d 100644
> > --- a/mm/vmalloc.c
> > +++ b/mm/vmalloc.c
> > @@ -3508,9 +3508,9 @@ EXPORT_SYMBOL_GPL(vmap_pfn);
> >
> >  static inline unsigned int
> >  vm_area_alloc_pages(gfp_t gfp, int nid,
> > -             unsigned int order, unsigned int nr_pages, struct page **pages)
> > +             unsigned int *page_order, unsigned int nr_pages, struct page **pages)
> >  {
> > -     unsigned int nr_allocated = 0;
> > +     unsigned int nr_allocated = 0, order = *page_order;
> >       gfp_t alloc_gfp = gfp;
> >       bool nofail = gfp & __GFP_NOFAIL;
> >       struct page *page;
> > @@ -3611,6 +3611,7 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
> >               cond_resched();
> >               nr_allocated += 1U << order;
> >       }
> > +     *page_order = order;
> >
> >       return nr_allocated;
> >  }
> > @@ -3654,7 +3655,7 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
> >       page_order = vm_area_page_order(area);
> >
> >       area->nr_pages = vm_area_alloc_pages(gfp_mask | __GFP_NOWARN,
> > -             node, page_order, nr_small_pages, area->pages);
> > +             node, &page_order, nr_small_pages, area->pages);
> >
> >       atomic_long_add(area->nr_pages, &nr_vmalloc_pages);
> >       if (gfp_mask & __GFP_ACCOUNT) {
> > @@ -3686,6 +3687,10 @@ static void *__vmalloc_area_node(struct vm_struct *area, gfp_t gfp_mask,
> >               goto fail;
> >       }
> >
> > +
> > +     set_vm_area_page_order(area, page_order);
> > +     page_shift = page_order + PAGE_SHIFT;
> > +
> >       /*
> >        * page tables allocations ignore external gfp mask, enforce it
> >        * by the scope API
> >
> The logic of this patch is somewhat similar to my first one. If high order
> allocation fails, it will go normal mapping.
>
> However I also save the fallback position. The ones before this position are
> used for huge mapping, the ones >= position for normal mapping as Barry said.
> "support the combination of PMD and PTE mapping". this  will take some
> times as it needs to address the corner cases and do some tests.
>
> IMO, the draft can fix the current issue, it also does not have significant side
> effects. Barry, what do you think about this patch? If you think it's okay,
> I will split this patch into two: one to remove the VM_ALLOW_HUGE_VMAP and the
> other to address the current mapping issue.

Yes, it's acceptable, even though it's not perfect. However,
addressing the mapping
issues is an urgent requirement. Memory corruption is currently
occurring, and we
need to ensure the fix reaches the stable kernel and mainline as soon
as possible.

Removing VM_ALLOW_HUGE_VMAP in kvmalloc is not as urgent. with Baoquan's
patch, we can even extend the fallback to non-nofail case. then maybe we can
remain VM_ALLOW_HUGE_VMAP of kvmalloc. This at least fixes one problem of
kvmalloc: we are likely to fail because it is really difficult to get
2MB contiguous
memory from buddy while memory is fragmented.

diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index caf032f0bd69..6f47b01cbe2e 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -3585,11 +3585,11 @@ vm_area_alloc_pages(gfp_t gfp, int nid,
                else
                        page = alloc_pages_node_noprof(nid, alloc_gfp, order);
                if (unlikely(!page)) {
-                       if (!nofail)
+                       if (!nofail && order == 0)
                                break;
-
+                       if (nofail)
+                               alloc_gfp |= __GFP_NOFAIL;
                        /* fall back to the zero order allocations */
-                       alloc_gfp |= __GFP_NOFAIL;
                        order = 0;
                        continue;
                }

Other two optimizations can be deferred tasks
1. to save memory—such as avoiding allocating 4MB when users request 2.1MB
with kvmalloc.

2. to do mixed and adaptive mapping, for example, for the 2.1kvmalloc,
 * if the first 2MB is contiguous, we map the 0~2MB as PMD and 2MB~2.1MB as PTE;
 * if the first 2MB is not contiguous, we map the whole 0~2.1MB as PTE

>
> --
> help you, help me,
> Hailong.

Thanks
Barry





[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux