diff options
author | Henry Burns <henryburns@google.com> | 2019-07-16 19:26:21 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-16 22:23:21 -0400 |
commit | c92d2f38563db20c20c8db2f98fa1349290477d5 (patch) | |
tree | d4671d744b5ec48bd7c9ad15ac780f537687aac0 | |
parent | be03074c9af25d06cf8e9ebddfcd284c0bf7f947 (diff) |
mm/z3fold.c: reinitialize zhdr structs after migration
z3fold_page_migration() calls memcpy(new_zhdr, zhdr, PAGE_SIZE).
However, zhdr contains fields that can't be directly coppied over (ex:
list_head, a circular linked list). We only need to initialize the
linked lists in new_zhdr, as z3fold_isolate_page() already ensures that
these lists are empty
Additionally it is possible that zhdr->work has been placed in a
workqueue. In this case we shouldn't migrate the page, as zhdr->work
references zhdr as opposed to new_zhdr.
Link: http://lkml.kernel.org/r/20190716000520.230595-1-henryburns@google.com
Fixes: 1f862989b04ade61d3 ("mm/z3fold.c: support page migration")
Signed-off-by: Henry Burns <henryburns@google.com>
Reviewed-by: Shakeel Butt <shakeelb@google.com>
Cc: Vitaly Vul <vitaly.vul@sony.com>
Cc: Vitaly Wool <vitalywool@gmail.com>
Cc: Jonathan Adams <jwadams@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | mm/z3fold.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/mm/z3fold.c b/mm/z3fold.c index 70008a8fed95..6c72b18d8b9c 100644 --- a/mm/z3fold.c +++ b/mm/z3fold.c | |||
@@ -1357,12 +1357,22 @@ static int z3fold_page_migrate(struct address_space *mapping, struct page *newpa | |||
1357 | z3fold_page_unlock(zhdr); | 1357 | z3fold_page_unlock(zhdr); |
1358 | return -EBUSY; | 1358 | return -EBUSY; |
1359 | } | 1359 | } |
1360 | if (work_pending(&zhdr->work)) { | ||
1361 | z3fold_page_unlock(zhdr); | ||
1362 | return -EAGAIN; | ||
1363 | } | ||
1360 | new_zhdr = page_address(newpage); | 1364 | new_zhdr = page_address(newpage); |
1361 | memcpy(new_zhdr, zhdr, PAGE_SIZE); | 1365 | memcpy(new_zhdr, zhdr, PAGE_SIZE); |
1362 | newpage->private = page->private; | 1366 | newpage->private = page->private; |
1363 | page->private = 0; | 1367 | page->private = 0; |
1364 | z3fold_page_unlock(zhdr); | 1368 | z3fold_page_unlock(zhdr); |
1365 | spin_lock_init(&new_zhdr->page_lock); | 1369 | spin_lock_init(&new_zhdr->page_lock); |
1370 | INIT_WORK(&new_zhdr->work, compact_page_work); | ||
1371 | /* | ||
1372 | * z3fold_page_isolate() ensures that new_zhdr->buddy is empty, | ||
1373 | * so we only have to reinitialize it. | ||
1374 | */ | ||
1375 | INIT_LIST_HEAD(&new_zhdr->buddy); | ||
1366 | new_mapping = page_mapping(page); | 1376 | new_mapping = page_mapping(page); |
1367 | __ClearPageMovable(page); | 1377 | __ClearPageMovable(page); |
1368 | ClearPagePrivate(page); | 1378 | ClearPagePrivate(page); |