mm/swap: skip readahead only when swap slot cache is enabled
authorHuang Ying <ying.huang@intel.com>
Wed, 22 Feb 2017 23:45:46 +0000 (15:45 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Feb 2017 00:41:30 +0000 (16:41 -0800)
Because during swap off, a swap entry may have swap_map[] ==
SWAP_HAS_CACHE (for example, just allocated).  If we return NULL in
__read_swap_cache_async(), the swap off will abort.  So when swap slot
cache is disabled, (for swap off), we will wait for page to be put into
swap cache in such race condition.  This should not be a problem for swap
slot cache, because swap slot cache should be drained after clearing
swap_slot_cache_enabled.

[ying.huang@intel.com: fix memory leak in __read_swap_cache_async()]
Link: http://lkml.kernel.org/r/874lzt6znd.fsf@yhuang-dev.intel.com
Link: http://lkml.kernel.org/r/5e2c5f6abe8e6eb0797408897b1bba80938e9b9d.1484082593.git.tim.c.chen@linux.intel.com
Signed-off-by: "Huang, Ying" <ying.huang@intel.com>
Signed-off-by: Tim Chen <tim.c.chen@linux.intel.com>
Cc: Aaron Lu <aaron.lu@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Christian Borntraeger <borntraeger@de.ibm.com>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Hillf Danton <hillf.zj@alibaba-inc.com>
Cc: Huang Ying <ying.huang@intel.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Jonathan Corbet <corbet@lwn.net> escreveu:
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Michal Hocko <mhocko@kernel.org>
Cc: Minchan Kim <minchan@kernel.org>
Cc: Rik van Riel <riel@redhat.com>
Cc: Shaohua Li <shli@kernel.org>
Cc: Vladimir Davydov <vdavydov.dev@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
include/linux/swap_slots.h
mm/swap_slots.c
mm/swap_state.c

index ba5623b27c60407924c64886cb2ba8e795a9c5fd..6ef92d17633da7eb1c138a9e79195cf644f9038d 100644 (file)
@@ -25,4 +25,6 @@ void reenable_swap_slots_cache_unlock(void);
 int enable_swap_slots_cache(void);
 int free_swap_slot(swp_entry_t entry);
 
+extern bool swap_slot_cache_enabled;
+
 #endif /* _LINUX_SWAP_SLOTS_H */
index ebf4f1cbac0452ef431ccf398293a4a37008e197..9b5bc86f96ad731269e2051719583f168a74bc51 100644 (file)
@@ -36,7 +36,7 @@
 
 static DEFINE_PER_CPU(struct swap_slots_cache, swp_slots);
 static bool    swap_slot_cache_active;
-static bool    swap_slot_cache_enabled;
+bool   swap_slot_cache_enabled;
 static bool    swap_slot_cache_initialized;
 DEFINE_MUTEX(swap_slots_cache_mutex);
 /* Serialize swap slots cache enable/disable operations */
index e1f07cafecaacdcf63f6758ad15a27b766aebe4d..473b71e052a8ed29df7c496af747e2b43491c782 100644 (file)
@@ -324,9 +324,16 @@ struct page *__read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
                if (found_page)
                        break;
 
-               /* Just skip read ahead for unused swap slot */
-               if (!__swp_swapcount(entry))
-                       return NULL;
+               /*
+                * Just skip read ahead for unused swap slot.
+                * During swap_off when swap_slot_cache is disabled,
+                * we have to handle the race between putting
+                * swap entry in swap cache and marking swap slot
+                * as SWAP_HAS_CACHE.  That's done in later part of code or
+                * else swap_off will be aborted if we return NULL.
+                */
+               if (!__swp_swapcount(entry) && swap_slot_cache_enabled)
+                       break;
 
                /*
                 * Get a new page to read into from swap.