diff options
| -rw-r--r-- | mm/memfd_luo.c | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c index 1c9510289312..b8edb9f981d7 100644 --- a/mm/memfd_luo.c +++ b/mm/memfd_luo.c @@ -146,7 +146,6 @@ static int memfd_luo_preserve_folios(struct file *file, for (i = 0; i < nr_folios; i++) { struct memfd_luo_folio_ser *pfolio = &folios_ser[i]; struct folio *folio = folios[i]; - unsigned int flags = 0; err = kho_preserve_folio(folio); if (err) @@ -154,8 +153,26 @@ static int memfd_luo_preserve_folios(struct file *file, folio_lock(folio); - if (folio_test_dirty(folio)) - flags |= MEMFD_LUO_FOLIO_DIRTY; + /* + * A dirty folio is one which has been written to. A clean folio + * is its opposite. Since a clean folio does not carry user + * data, it can be freed by page reclaim under memory pressure. + * + * Saving the dirty flag at prepare() time doesn't work since it + * can change later. Saving it at freeze() also won't work + * because the dirty bit is normally synced at unmap and there + * might still be a mapping of the file at freeze(). + * + * To see why this is a problem, say a folio is clean at + * preserve, but gets dirtied later. The pfolio flags will mark + * it as clean. After retrieve, the next kernel might try to + * reclaim this folio under memory pressure, losing user data. + * + * Unconditionally mark it dirty to avoid this problem. This + * comes at the cost of making clean folios un-reclaimable after + * live update. + */ + folio_mark_dirty(folio); /* * If the folio is not uptodate, it was fallocated but never @@ -174,12 +191,11 @@ static int memfd_luo_preserve_folios(struct file *file, flush_dcache_folio(folio); folio_mark_uptodate(folio); } - flags |= MEMFD_LUO_FOLIO_UPTODATE; folio_unlock(folio); pfolio->pfn = folio_pfn(folio); - pfolio->flags = flags; + pfolio->flags = MEMFD_LUO_FOLIO_DIRTY | MEMFD_LUO_FOLIO_UPTODATE; pfolio->index = folio->index; } |
