Skip to content

Commit 25cd241

Browse files
hnazakpm00
authored andcommitted
mm: zswap: fix data loss on SWP_SYNCHRONOUS_IO devices
Zhongkun He reports data corruption when combining zswap with zram. The issue is the exclusive loads we're doing in zswap. They assume that all reads are going into the swapcache, which can assume authoritative ownership of the data and so the zswap copy can go. However, zram files are marked SWP_SYNCHRONOUS_IO, and faults will try to bypass the swapcache. This results in an optimistic read of the swap data into a page that will be dismissed if the fault fails due to races. In this case, zswap mustn't drop its authoritative copy. Link: https://lore.kernel.org/all/CACSyD1N+dUvsu8=zV9P691B9bVq33erwOXNTmEaUbi9DrDeJzw@mail.gmail.com/ Fixes: b9c91c4 ("mm: zswap: support exclusive loads") Link: https://lkml.kernel.org/r/[email protected] Signed-off-by: Johannes Weiner <[email protected]> Reported-by: Zhongkun He <[email protected]> Tested-by: Zhongkun He <[email protected]> Acked-by: Yosry Ahmed <[email protected]> Acked-by: Barry Song <[email protected]> Reviewed-by: Chengming Zhou <[email protected]> Reviewed-by: Nhat Pham <[email protected]> Acked-by: Chris Li <[email protected]> Cc: <[email protected]> [6.5+] Signed-off-by: Andrew Morton <[email protected]>
1 parent 8c86437 commit 25cd241

File tree

1 file changed

+19
-4
lines changed

1 file changed

+19
-4
lines changed

mm/zswap.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1636,6 +1636,7 @@ bool zswap_load(struct folio *folio)
16361636
swp_entry_t swp = folio->swap;
16371637
pgoff_t offset = swp_offset(swp);
16381638
struct page *page = &folio->page;
1639+
bool swapcache = folio_test_swapcache(folio);
16391640
struct zswap_tree *tree = swap_zswap_tree(swp);
16401641
struct zswap_entry *entry;
16411642
u8 *dst;
@@ -1648,7 +1649,20 @@ bool zswap_load(struct folio *folio)
16481649
spin_unlock(&tree->lock);
16491650
return false;
16501651
}
1651-
zswap_rb_erase(&tree->rbroot, entry);
1652+
/*
1653+
* When reading into the swapcache, invalidate our entry. The
1654+
* swapcache can be the authoritative owner of the page and
1655+
* its mappings, and the pressure that results from having two
1656+
* in-memory copies outweighs any benefits of caching the
1657+
* compression work.
1658+
*
1659+
* (Most swapins go through the swapcache. The notable
1660+
* exception is the singleton fault on SWP_SYNCHRONOUS_IO
1661+
* files, which reads into a private page and may free it if
1662+
* the fault fails. We remain the primary owner of the entry.)
1663+
*/
1664+
if (swapcache)
1665+
zswap_rb_erase(&tree->rbroot, entry);
16521666
spin_unlock(&tree->lock);
16531667

16541668
if (entry->length)
@@ -1663,9 +1677,10 @@ bool zswap_load(struct folio *folio)
16631677
if (entry->objcg)
16641678
count_objcg_event(entry->objcg, ZSWPIN);
16651679

1666-
zswap_entry_free(entry);
1667-
1668-
folio_mark_dirty(folio);
1680+
if (swapcache) {
1681+
zswap_entry_free(entry);
1682+
folio_mark_dirty(folio);
1683+
}
16691684

16701685
return true;
16711686
}

0 commit comments

Comments
 (0)