Re: [PATCH RFC 04/13] mm/huge_memory: split the routine for splitting anon and file folio

Kairui Song <[email protected]>
Newsgroups gmane.linux.kernel,gmane.linux.kernel.mm
Message-ID <CAMgjq7Bb4tunWb8wxX+TwR2iLFub4dQciebSJUKwUrJ3udX9Bw@mail.gmail.com>
On Sun, Aug 9, 2026 at 2:52 AM Zi Yan <[email protected]> wrote:
>
> On Fri Aug 7, 2026 at 5:17 PM EDT, Kairui Song via B4 Relay wrote:
> > From: Kairui Song <[email protected]>
> >
> > No functional change intended. Before adding more logic, split
> > __folio_freeze_and_split_unmapped() into an anon and a file variant so
> > each path can evolve independently. The two paths shared little beyond
> > the folio freeze call, the LRU locking, and the unfreeze skeleton, but
> > differed in all other per-folio bookkeeping and routines.
>
> While at it, can you rename __split_unmapped_folio() to
> __split_frozen_folio() to reflect the actual folio state? It is causing
> confusion and people tried to use __split_unmapped_folio() on non frozen
> folios.

Will do.

> > @@ -3987,24 +3984,73 @@ static int __folio_freeze_and_split_unmapped(struct folio *folio, unsigned int n
> >               rcu_read_unlock();
> >       }
> >
> > -     if (mapping) {
> > +     if (folio_test_swapcache(folio))
> > +             ci = swap_cluster_get_and_lock(folio);
> > +
> > +     if (do_lru)
> > +             lruvec = folio_lruvec_lock(folio);
> > +
> > +     ret = __split_unmapped_folio(folio, new_order, split_at, NULL,
> > +                                  NULL, split_type);
> > +
> > +     /*
> > +      * Unfreeze the after-split folios and put them back to the right
> > +      * place, keeping the head @folio frozen until the end. While the
> > +      * folio is in the swap cache, the sub entries must be updated with
> > +      * their after-split folios before the head is unfrozen, so a
> > +      * concurrent swap_cache_get_folio() cannot return the head folio
> > +      * for a sub entry. Keeping the head frozen throughout also stops a
> > +      * parallel folio_try_get() from observing a partially split folio.
> > +      */
> > +     for (new_folio = folio_next(folio); new_folio != end_folio;
> > +          new_folio = folio_next(new_folio)) {
>
> Please keep the existing for loop pattern by using next =
> folio_next(new_folio) in the loop buddy.
>
> Hugh pointed out an issue when I did the above for loop pattern[1].
> Basically, folio_next() reads folio_nr_pages() and relies on a stable
> new_folio input. In my old code, the input of folio_next() can be freed
> and causing oops. In your code, that does not apply, but it can bite
> people in the future the loop body changes and new_folio's lifetime ends
> before the for loop finishes.
>
> Maybe add a comment to explain why next = folio_next(new_folio) should
> be used.

Sure, I'll try if a macro can be used to deduplicate it.

>
> [1] https://lore.kernel.org/all/[email protected]/
>

...

> > @@ -4231,10 +4259,14 @@ static int __folio_split(struct folio *folio, unsigned int new_order,
> >                       ret = -EAGAIN;
> >                       goto fail;
> >               }
> > +             ret = __folio_freeze_split_unmapped_file(folio, new_order, split_at, &xas, mapping,
> > +                                                      true, list, split_type, end,
> > +                                                      &nr_shmem_dropped);
> > +     } else {
> > +             ret = __folio_freeze_split_unmapped_anon(folio, new_order, split_at, true,
> > +                                                      list, split_type);
> >       }
> >
> > -     ret = __folio_freeze_and_split_unmapped(folio, new_order, split_at, &xas, mapping,
> > -                                             true, list, split_type, end, &nr_shmem_dropped);
> >  fail:
> >       if (mapping)
> >               xas_unlock(&xas);
> > @@ -4334,9 +4366,8 @@ int folio_split_unmapped(struct folio *folio, unsigned int new_order)
> >               return -EAGAIN;
> >
> >       local_irq_disable();
> > -     ret = __folio_freeze_and_split_unmapped(folio, new_order, &folio->page, NULL,
> > -                                             NULL, false, NULL, SPLIT_TYPE_UNIFORM,
> > -                                             0, NULL);
> > +     ret = __folio_freeze_split_unmapped_anon(folio, new_order, &folio->page,
> > +                                              false, NULL, SPLIT_TYPE_UNIFORM);
> >       local_irq_enable();
> >       return ret;
> >  }
>
> There are some code duplications but overall looks good to me. The lru
> lock, unfreeze loop, and the last unfreeze are replicated across two
> functions. I cannot think of an easy alternative. A tiny improvement
> might be instead of replicating unfreeze comments, changing one to point
> to the other one and asking the code should be in sync.

Good suggestion, thanks! I think code duplications could be further
reduced by a few macros or helpers. In following patches, removing
many if branches and streamlining the workflow actually improved it as
a whole, so I think it's worth it.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.