Move shmem_recalc_inode() out of the loop in memfd_luo_retrieve_folios()
to improve performance when restoring large memfds.
Currently, shmem_recalc_inode() is called for each folio during restore,
which is O(n) expensive operations. This patch collects the number of
successfully added folios and calls shmem_recalc_inode() once after the
loop completes, reducing complexity to O(1).
Additionally, fix the error path to also call shmem_recalc_inode() for
the folios that were successfully added before the error occurred.
Signed-off-by: Chenghao Duan <duanchenghao@kylinos.cn>
---
mm/memfd_luo.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
index b8edb9f981d7..5ddd3657d8be 100644
--- a/mm/memfd_luo.c
+++ b/mm/memfd_luo.c
@@ -397,6 +397,7 @@ static int memfd_luo_retrieve_folios(struct file *file,
struct folio *folio;
int err = -EIO;
long i;
+ u64 nr_added = 0;
for (i = 0; i < nr_folios; i++) {
const struct memfd_luo_folio_ser *pfolio = &folios_ser[i];
@@ -448,12 +449,15 @@ static int memfd_luo_retrieve_folios(struct file *file,
goto unlock_folio;
}
- shmem_recalc_inode(inode, 1, 0);
+ nr_added++;
folio_add_lru(folio);
folio_unlock(folio);
folio_put(folio);
}
+ if (nr_added)
+ shmem_recalc_inode(inode, nr_added, 0);
+
return 0;
unlock_folio:
@@ -472,6 +476,9 @@ static int memfd_luo_retrieve_folios(struct file *file,
folio_put(folio);
}
+ if (nr_added)
+ shmem_recalc_inode(inode, nr_added, 0);
+
return err;
}
--
2.25.1
On Thu, Mar 19 2026, Chenghao Duan wrote:
> Move shmem_recalc_inode() out of the loop in memfd_luo_retrieve_folios()
> to improve performance when restoring large memfds.
>
> Currently, shmem_recalc_inode() is called for each folio during restore,
> which is O(n) expensive operations. This patch collects the number of
> successfully added folios and calls shmem_recalc_inode() once after the
> loop completes, reducing complexity to O(1).
>
> Additionally, fix the error path to also call shmem_recalc_inode() for
> the folios that were successfully added before the error occurred.
>
> Signed-off-by: Chenghao Duan <duanchenghao@kylinos.cn>
> ---
> mm/memfd_luo.c | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
> index b8edb9f981d7..5ddd3657d8be 100644
> --- a/mm/memfd_luo.c
> +++ b/mm/memfd_luo.c
> @@ -397,6 +397,7 @@ static int memfd_luo_retrieve_folios(struct file *file,
> struct folio *folio;
> int err = -EIO;
> long i;
> + u64 nr_added = 0;
>
> for (i = 0; i < nr_folios; i++) {
> const struct memfd_luo_folio_ser *pfolio = &folios_ser[i];
> @@ -448,12 +449,15 @@ static int memfd_luo_retrieve_folios(struct file *file,
> goto unlock_folio;
> }
>
> - shmem_recalc_inode(inode, 1, 0);
> + nr_added++;
https://sashiko.dev/#/patchset/20260319012845.29570-1-duanchenghao%40kylinos.cn
AI review picked up a real bug here:
Since memfd files can use large folios, should nr_added track the
number of pages instead of the number of folios?
shmem_recalc_inode() expects the number of pages. Passing the number
of folios might under-account blocks and bypass tmpfs limits or
quotas.
Also, shmem_inode_acct_blocks() earlier in the loop is hardcoded to
1, which might have the same issue.
If THP is being used, we should account for nr_pages instead of
nr_folios. Can you please also add a fix for this with your series? Just
so we fix the bugs the code already has before refactoring it.
> folio_add_lru(folio);
> folio_unlock(folio);
> folio_put(folio);
> }
>
> + if (nr_added)
> + shmem_recalc_inode(inode, nr_added, 0);
Nit: it is very very likely that nr_added > 0. And shmem_recalc_inode()
can deal with 0 nr_added. So please drop this if check and call it
directly.
Other than this, the patch LGTM. Thanks for working on this!
> +
> return 0;
>
> unlock_folio:
> @@ -472,6 +476,9 @@ static int memfd_luo_retrieve_folios(struct file *file,
> folio_put(folio);
> }
>
> + if (nr_added)
> + shmem_recalc_inode(inode, nr_added, 0);
> +
> return err;
> }
--
Regards,
Pratyush Yadav
On Wed, Mar 18, 2026 at 9:29 PM Chenghao Duan <duanchenghao@kylinos.cn> wrote:
>
> Move shmem_recalc_inode() out of the loop in memfd_luo_retrieve_folios()
> to improve performance when restoring large memfds.
>
> Currently, shmem_recalc_inode() is called for each folio during restore,
> which is O(n) expensive operations. This patch collects the number of
> successfully added folios and calls shmem_recalc_inode() once after the
> loop completes, reducing complexity to O(1).
>
> Additionally, fix the error path to also call shmem_recalc_inode() for
> the folios that were successfully added before the error occurred.
>
> Signed-off-by: Chenghao Duan <duanchenghao@kylinos.cn>
> ---
> mm/memfd_luo.c | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
> index b8edb9f981d7..5ddd3657d8be 100644
> --- a/mm/memfd_luo.c
> +++ b/mm/memfd_luo.c
> @@ -397,6 +397,7 @@ static int memfd_luo_retrieve_folios(struct file *file,
> struct folio *folio;
> int err = -EIO;
> long i;
> + u64 nr_added = 0;
nit: I perfer RCT for local variables order, but it is not followed in
this file anyway.
>
> for (i = 0; i < nr_folios; i++) {
> const struct memfd_luo_folio_ser *pfolio = &folios_ser[i];
> @@ -448,12 +449,15 @@ static int memfd_luo_retrieve_folios(struct file *file,
> goto unlock_folio;
> }
>
> - shmem_recalc_inode(inode, 1, 0);
> + nr_added++;
> folio_add_lru(folio);
> folio_unlock(folio);
> folio_put(folio);
> }
>
> + if (nr_added)
> + shmem_recalc_inode(inode, nr_added, 0);
> +
> return 0;
>
> unlock_folio:
> @@ -472,6 +476,9 @@ static int memfd_luo_retrieve_folios(struct file *file,
> folio_put(folio);
> }
>
> + if (nr_added)
> + shmem_recalc_inode(inode, nr_added, 0);
> +
Reviewed-by: Pasha Tatashin <pasha.tatashin@soleen.com>
On Thu, Mar 19 2026, Pasha Tatashin wrote: > On Wed, Mar 18, 2026 at 9:29 PM Chenghao Duan <duanchenghao@kylinos.cn> wrote: >> >> Move shmem_recalc_inode() out of the loop in memfd_luo_retrieve_folios() >> to improve performance when restoring large memfds. >> >> Currently, shmem_recalc_inode() is called for each folio during restore, >> which is O(n) expensive operations. This patch collects the number of >> successfully added folios and calls shmem_recalc_inode() once after the >> loop completes, reducing complexity to O(1). >> >> Additionally, fix the error path to also call shmem_recalc_inode() for >> the folios that were successfully added before the error occurred. >> >> Signed-off-by: Chenghao Duan <duanchenghao@kylinos.cn> >> --- >> mm/memfd_luo.c | 9 ++++++++- >> 1 file changed, 8 insertions(+), 1 deletion(-) >> >> diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c >> index b8edb9f981d7..5ddd3657d8be 100644 >> --- a/mm/memfd_luo.c >> +++ b/mm/memfd_luo.c >> @@ -397,6 +397,7 @@ static int memfd_luo_retrieve_folios(struct file *file, >> struct folio *folio; >> int err = -EIO; >> long i; >> + u64 nr_added = 0; > > nit: I perfer RCT for local variables order, but it is not followed in > this file anyway. It is though, for the most part. I also prefer this so as much as I could I followed it, but sometimes if you want to assign variables at declaration, it isn't always possible. Anyway, RCT would be nice to have indeed. [...] -- Regards, Pratyush Yadav
© 2016 - 2026 Red Hat, Inc.