59 lines
1.8 KiB
Plaintext
59 lines
1.8 KiB
Plaintext
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
|
|
@@ -128,10 +128,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
|
|
@@ -2302,7 +2302,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)];
|
|
}
|
|
|