summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mm/memfd_luo.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
index 785f26aa58c0..71d64bcc9c2b 100644
--- a/mm/memfd_luo.c
+++ b/mm/memfd_luo.c
@@ -152,10 +152,31 @@ static int memfd_luo_preserve_folios(struct file *file,
if (err)
goto err_unpreserve;
+ folio_lock(folio);
+
if (folio_test_dirty(folio))
flags |= MEMFD_LUO_FOLIO_DIRTY;
- if (folio_test_uptodate(folio))
- flags |= MEMFD_LUO_FOLIO_UPTODATE;
+
+ /*
+ * If the folio is not uptodate, it was fallocated but never
+ * used. Saving this flag at prepare() doesn't work since it
+ * might change later when someone uses the folio.
+ *
+ * Since we have taken the performance penalty of allocating,
+ * zeroing, and pinning all the folios in the holes, take a bit
+ * more and zero all non-uptodate folios too.
+ *
+ * NOTE: For someone looking to improve preserve performance,
+ * this is a good place to look.
+ */
+ if (!folio_test_uptodate(folio)) {
+ folio_zero_range(folio, 0, folio_size(folio));
+ flush_dcache_folio(folio);
+ folio_mark_uptodate(folio);
+ }
+ flags |= MEMFD_LUO_FOLIO_UPTODATE;
+
+ folio_unlock(folio);
pfolio->pfn = folio_pfn(folio);
pfolio->flags = flags;