Skip to content

Commit

Permalink
mm/z3fold.c: claim page in the beginning of free
Browse files Browse the repository at this point in the history
There's a really hard to reproduce race in z3fold between z3fold_free()
and z3fold_reclaim_page().  z3fold_reclaim_page() can claim the page
after z3fold_free() has checked if the page was claimed and
z3fold_free() will then schedule this page for compaction which may in
turn lead to random page faults (since that page would have been
reclaimed by then).

Fix that by claiming page in the beginning of z3fold_free() and not
forgetting to clear the claim in the end.

[[email protected]: v2]
  Link: http://lkml.kernel.org/r/20190928113456.152742cf@bigdell
Link: http://lkml.kernel.org/r/[email protected]
Signed-off-by: Vitaly Wool <[email protected]>
Reported-by: Markus Linnala <[email protected]>
Cc: Dan Streetman <[email protected]>
Cc: Vlastimil Babka <[email protected]>
Cc: Henry Burns <[email protected]>
Cc: Shakeel Butt <[email protected]>
Cc: Markus Linnala <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
vwool authored and torvalds committed Oct 7, 2019
1 parent b0f53db commit 5b6807d
Showing 1 changed file with 8 additions and 2 deletions.
10 changes: 8 additions & 2 deletions mm/z3fold.c
Original file line number Diff line number Diff line change
Expand Up @@ -998,17 +998,19 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
struct z3fold_header *zhdr;
struct page *page;
enum buddy bud;
bool page_claimed;

zhdr = handle_to_z3fold_header(handle);
page = virt_to_page(zhdr);
page_claimed = test_and_set_bit(PAGE_CLAIMED, &page->private);

if (test_bit(PAGE_HEADLESS, &page->private)) {
/* if a headless page is under reclaim, just leave.
* NB: we use test_and_set_bit for a reason: if the bit
* has not been set before, we release this page
* immediately so we don't care about its value any more.
*/
if (!test_and_set_bit(PAGE_CLAIMED, &page->private)) {
if (!page_claimed) {
spin_lock(&pool->lock);
list_del(&page->lru);
spin_unlock(&pool->lock);
Expand Down Expand Up @@ -1044,13 +1046,15 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
atomic64_dec(&pool->pages_nr);
return;
}
if (test_bit(PAGE_CLAIMED, &page->private)) {
if (page_claimed) {
/* the page has not been claimed by us */
z3fold_page_unlock(zhdr);
return;
}
if (unlikely(PageIsolated(page)) ||
test_and_set_bit(NEEDS_COMPACTING, &page->private)) {
z3fold_page_unlock(zhdr);
clear_bit(PAGE_CLAIMED, &page->private);
return;
}
if (zhdr->cpu < 0 || !cpu_online(zhdr->cpu)) {
Expand All @@ -1060,10 +1064,12 @@ static void z3fold_free(struct z3fold_pool *pool, unsigned long handle)
zhdr->cpu = -1;
kref_get(&zhdr->refcount);
do_compact_page(zhdr, true);
clear_bit(PAGE_CLAIMED, &page->private);
return;
}
kref_get(&zhdr->refcount);
queue_work_on(zhdr->cpu, pool->compact_wq, &zhdr->work);
clear_bit(PAGE_CLAIMED, &page->private);
z3fold_page_unlock(zhdr);
}

Expand Down

0 comments on commit 5b6807d

Please sign in to comment.