Re: [RFC PATCH v5 2/4] mm: distinguish large folio swap allocation failures

Barry Song <[email protected]>
Newsgroups org.kernel.vger.cgroups,org.kernel.vger.linux-kernel,org.kvack.linux-mm
Message-ID <CAGsJ_4wL0fiVji16XCb37XYZh3s8RetndxPq76d=whhaxH4tcA@mail.gmail.com>
On Fri, Aug 7, 2026 at 4:29 PM Kairui Song <[email protected]> wrote:
>
> On Thu, Jul 30, 2026 at 08:23:02PM +0800, Xueyuan Chen wrote:
> > folio_alloc_swap() reports most allocation failures with a generic
> > negative error code. Reclaim cannot tell whether splitting a large folio
> > could make progress or whether there is no backing space at all.
> >
> > Keep the global free swap count and the remaining hierarchical memcg swap
> > margin as separate inputs. The memcg charge path reports only its own
> > margin; folio_alloc_swap() combines the two layers when classifying an
> > allocation failure.
> >
> > Return -E2BIG for large folios when a smaller allocation might still fit,
> > -ENOSPC when no global swap space is available, and -ENOMEM when the
> > failure is not helped by splitting.
> >
> > For early large-folio rejections, check global and memcg swap availability
> > instead of returning -E2BIG unconditionally. On a memcg charge failure,
> > swap slot allocation has already succeeded, so use the remaining memcg
> > margin to decide whether a smaller charge might fit.
> >
> > This only refines folio_alloc_swap() return codes. The reclaim callers are
> > updated separately.
> >
> > Suggested-by: Barry Song <[email protected]>
> > Suggested-by: Youngjun Park <[email protected]>
> > Signed-off-by: Xueyuan Chen <[email protected]>
> > ---
> >  include/linux/swap.h | 16 ++++++++++++----
> >  mm/memcontrol.c      | 32 +++++++++++++++++++++++++++++++-
> >  mm/swapfile.c        | 32 ++++++++++++++++++++++++--------
> >  3 files changed, 67 insertions(+), 13 deletions(-)
> >
>
> Hello Xueyuan,
>
> Thanks for the patch!
>
> > diff --git a/include/linux/swap.h b/include/linux/swap.h
> > index 0544b2ec4c56..7d12058174ae 100644
> > --- a/include/linux/swap.h
> > +++ b/include/linux/swap.h
> > @@ -509,12 +509,13 @@ static inline void folio_throttle_swaprate(struct folio *folio, gfp_t gfp)
> >  #endif
> >
> >  #if defined(CONFIG_MEMCG) && defined(CONFIG_SWAP)
> > -int __mem_cgroup_try_charge_swap(struct folio *folio);
> > -static inline int mem_cgroup_try_charge_swap(struct folio *folio)
> > +int __mem_cgroup_try_charge_swap(struct folio *folio, long *swap_margin);
> > +static inline int mem_cgroup_try_charge_swap(struct folio *folio,
> > +                                          long *swap_margin)
>
> Am I the only one that feel this returning argument is a bit ugly? See below..
>
> > +/**
> > + * mem_cgroup_get_folio_swap_margin - get a folio's memcg swap margin
> > + * @folio: folio whose memcg margin is queried
> > + *
> > + * Return: Remaining chargeable pages in the folio's memcg hierarchy.
> > + */
> > +long mem_cgroup_get_folio_swap_margin(struct folio *folio)
> > +{
> > +     long swap_margin = PAGE_COUNTER_MAX;
> > +     struct mem_cgroup *memcg;
> > +     struct obj_cgroup *objcg;
> > +
> > +     if (mem_cgroup_disabled() || do_memsw_account())
> > +             return swap_margin;
> > +
> > +     objcg = folio_objcg(folio);
> > +     if (!objcg)
> > +             return swap_margin;
> > +
> > +     rcu_read_lock();
> > +     memcg = obj_cgroup_memcg(objcg);
> > +     swap_margin = page_counter_margin(&memcg->swap);
> > +     rcu_read_unlock();
> > +
> > +     return swap_margin;
> > +}
> > +
>
> Will is be good if we just always check the margin use this helper
> on alloc failure? Alloc failure should be a rather cold path I think?
>

The only disadvantage is that we don't get the margin together with
the charging failure. If this happens infrequently, it may not matter.
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.