Re: [PATCH v2] mm/memfd_luo: don't use memfd_pin_folios()
From: Mike Rapoport
Date: Wed Nov 04 2026 - 12:15:15 EST
> memfd_luo takes a snapshot of the folios in the file's mapping. To make
> sure the snapshot does not go out of sync, it pins the folios in the
> file via memfd_pin_folios(). The pinning also migrates the folios out of
> MIGRATE_MOVABLE to make sure doesn't land in KHO boot memory or in a CMA
> region.
>
> memfd_pin_folios() does not lock the folios. So it can race with
> shmem_writeout(). A folio returned by memfd_pin_folios() might already
> be in swap cache. This happens to work but is fragile. memfd_luo looks
> at folio flags and index on a folio that isn't in the memfd's page
> cache.
>
> In addition, memfd_pin_folios() needs the caller to allocate an array of
> folios. memfd_luo does not really need that since it will vmalloc
> folios_ser and store the information there anyway. The folios array is
> unnecessary overhead.
>
> Finally, memfd_pin_folios() fills in holes in the memfd. This makes
> preserving sparse memfds very expensive in both compute and memory.
> While this patch doesn't yet stop filling in the holes, it sets up the
> infrastructure to make it simpler.
>
> Fix all this by walking the page cache directly using shmem_get_folio()
> with SGP_CACHE. This returns a locked folio with an elevated refcount.
> memfd_luo holds that reference until the memfd is unpreserved. This
> blocks compaction, migration, etc.
>
> There is still a need to migrate folios out of MIGRATE_MOVABLE page
> blocks. This is because those might be CMA or KHO scratch. memfd_luo
> will hold a longterm reference to the folios so it will block migration
> in that pageblock. Introduce memfd_luo_migrate_folio() to do this.
>
> Also factor out folio unpreservation logic into memfd_luo_put_folios()
> and use it from memfd_luo_unpreserve_folios() and from error paths in
> memfd_luo_preserve_folios().
>
> Since shmem_get_folio() always returns uptodate folios, drop the folio
> zeroing logic.
>
> This change also improves preservation performance, shown in the table
> below.
>
> |------------------+----------+------------+-------|
> | memfd | baseline | this patch | delta |
> |------------------+----------+------------+-------|
> | 4K pages, 32 GiB | 748 ms | 600 ms | -20% |
> | THP, 4 GiB | 0.59 ms | 0.59 ms | 0% |
> | THP, 16 GiB | 2.99 ms | 2.61 ms | -13% |
> | THP, 32 GiB | 4.83 ms | 5.21 ms | +8% |
> | sparse, 32 GiB | 8695 ms | 7269 ms | -16% |
> |------------------+----------+------------+-------|
>
> Acked-by: Pasha Tatashin <pasha.tatashin@xxxxxxxxxx>
> Signed-off-by: Pratyush Yadav (Google) <pratyush@xxxxxxxxxx>
With a few nits below
Reviewed-by: Mike Rapoport (Microsoft) <rppt@xxxxxxxxxx>
> +/*
> + * Move a folio out of ZONE_MOVABLE or CMA, so it can be held until the next
"held until next kernel" - here and below - I feel that something is off
here, but can't pinpoint what exactly.
> + * kernel. Called with a reference on the unlocked folio, which is always
> + * dropped. The caller must look up the folio again afterwards.
I'm having hard time parsing "called with a reference" sentence :)
> +/*
> + * Look up the folio at @index, allocating it if needed, and make sure it can be
> + * held until the next kernel. Folios that are not longterm pinnable are migrated
> + * out first, retrying a few times if someone else has them isolated.
> + *
> + * On success, returns 0 with *@foliop locked and holding a reference.
> + */
> +static int memfd_luo_get_folio(struct inode *inode, pgoff_t index,
> + struct folio **foliop)
> +{
> + int err, busy_retries = 0;
> + struct folio *folio;
> +
> + for (;;) {
Won't
for (retry = 0; retry < MEMFD_LUO_MIGRATE_RETRIES; retry++) {
look better and the body simpler?
> + err = shmem_get_folio(inode, index, 0, &folio, SGP_CACHE);
> + if (err)
> + return err;
> +
> + if (likely(folio_is_longterm_pinnable(folio)))
> + break;
> +
> + folio_unlock(folio);
> + err = memfd_luo_migrate_folio(folio);
> + /* Someone else might have it isolated, retry a bit. */
> + if (err == -EBUSY && ++busy_retries < MEMFD_LUO_MIGRATE_RETRIES)
> + continue;
> + if (err)
> + return err;
> + }
> +
> + *foliop = folio;
> + return 0;
> +}
.
--
Sincerely yours,
Mike.