Skip to content

Commit ca56489

Browse files
lellomanakpm00
authored andcommitted
mm: zswap: fix potential memory corruption on duplicate store
While stress-testing zswap a memory corruption was happening when writing back pages. __frontswap_store used to check for duplicate entries before attempting to store a page in zswap, this was because if the store fails the old entry isn't removed from the tree. This change removes duplicate entries in zswap_store before the actual attempt. [[email protected]: add a warning and a comment, per Johannes] Link: https://lkml.kernel.org/r/[email protected] Link: https://lkml.kernel.org/r/[email protected] Fixes: 42c06a0 ("mm: kill frontswap") Signed-off-by: Domenico Cerasuolo <[email protected]> Acked-by: Johannes Weiner <[email protected]> Acked-by: Nhat Pham <[email protected]> Cc: Dan Streetman <[email protected]> Cc: Domenico Cerasuolo <[email protected]> Cc: Seth Jennings <[email protected]> Cc: Vitaly Wool <[email protected]> Signed-off-by: Andrew Morton <[email protected]>
1 parent 6f1bace commit ca56489

File tree

1 file changed

+20
-0
lines changed

1 file changed

+20
-0
lines changed

mm/zswap.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,6 +1218,19 @@ bool zswap_store(struct folio *folio)
12181218
if (!zswap_enabled || !tree)
12191219
return false;
12201220

1221+
/*
1222+
* If this is a duplicate, it must be removed before attempting to store
1223+
* it, otherwise, if the store fails the old page won't be removed from
1224+
* the tree, and it might be written back overriding the new data.
1225+
*/
1226+
spin_lock(&tree->lock);
1227+
dupentry = zswap_rb_search(&tree->rbroot, offset);
1228+
if (dupentry) {
1229+
zswap_duplicate_entry++;
1230+
zswap_invalidate_entry(tree, dupentry);
1231+
}
1232+
spin_unlock(&tree->lock);
1233+
12211234
/*
12221235
* XXX: zswap reclaim does not work with cgroups yet. Without a
12231236
* cgroup-aware entry LRU, we will push out entries system-wide based on
@@ -1333,7 +1346,14 @@ bool zswap_store(struct folio *folio)
13331346

13341347
/* map */
13351348
spin_lock(&tree->lock);
1349+
/*
1350+
* A duplicate entry should have been removed at the beginning of this
1351+
* function. Since the swap entry should be pinned, if a duplicate is
1352+
* found again here it means that something went wrong in the swap
1353+
* cache.
1354+
*/
13361355
while (zswap_rb_insert(&tree->rbroot, entry, &dupentry) == -EEXIST) {
1356+
WARN_ON(1);
13371357
zswap_duplicate_entry++;
13381358
zswap_invalidate_entry(tree, dupentry);
13391359
}

0 commit comments

Comments
 (0)