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.