qubes-linux-kernel/patches.suse/SoN-29-fix-swap_sync_page-race

59 lines
1.8 KiB
Plaintext
Raw Normal View History

From: NeilBrown <neilb@suse.de>
Subject: [PATCH 29/31] Cope with racy nature of sync_page in swap_sync_page
Patch-mainline: not yet
sync_page is called without that PageLock held. This means that,
for example, PageSwapCache can be cleared at any time.
We need to be careful not to put much trust any any part of the page.
So allow page_swap_info to return NULL of the page is no longer
in a SwapCache, and handle the NULL gracefully in swap_sync_page.
No other calls need to handle the NULL as that all hold PageLock,
so PageSwapCache cannot be cleared by surprise. Add a WARN_ON to
document this fact and help find out if I am wrong.
Acked-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: NeilBrown <neilb@suse.de>
Signed-off-by: Suresh Jayaraman <sjayaraman@suse.de>
---
mm/page_io.c | 5 +++++
mm/swapfile.c | 8 +++++++-
2 files changed, 12 insertions(+), 1 deletion(-)
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -127,10 +127,15 @@ out:
return ret;
}
+/* this comment ensure the patch applies to swap_sync_page
+ * and not swap_set_page_dirty by mistake
+ */
void swap_sync_page(struct page *page)
{
struct swap_info_struct *sis = page_swap_info(page);
+ if (!sis)
+ return;
if (sis->flags & SWP_FILE) {
struct address_space *mapping = sis->swap_file->f_mapping;
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -2242,7 +2242,13 @@ int swapcache_prepare(swp_entry_t entry)
struct swap_info_struct *page_swap_info(struct page *page)
{
swp_entry_t swap = { .val = page_private(page) };
- BUG_ON(!PageSwapCache(page));
+ if (!PageSwapCache(page) || !swap.val) {
+ /* This should only happen from sync_page.
+ * In other cases the page should be locked and
+ * should be in a SwapCache
+ */
+ return NULL;
+ }
return swap_info[swp_type(swap)];
}