Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mm/swap: skip readahead only when swap slot cache is enabled

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>

authored by

Huang Ying and committed by
Linus Torvalds
ba81f838 039939a6

+13 -4
+2
include/linux/swap_slots.h
··· 25 25 int enable_swap_slots_cache(void); 26 26 int free_swap_slot(swp_entry_t entry); 27 27 28 + extern bool swap_slot_cache_enabled; 29 + 28 30 #endif /* _LINUX_SWAP_SLOTS_H */
+1 -1
mm/swap_slots.c
··· 36 36 37 37 static DEFINE_PER_CPU(struct swap_slots_cache, swp_slots); 38 38 static bool swap_slot_cache_active; 39 - static bool swap_slot_cache_enabled; 39 + bool swap_slot_cache_enabled; 40 40 static bool swap_slot_cache_initialized; 41 41 DEFINE_MUTEX(swap_slots_cache_mutex); 42 42 /* Serialize swap slots cache enable/disable operations */
+10 -3
mm/swap_state.c
··· 324 324 if (found_page) 325 325 break; 326 326 327 - /* Just skip read ahead for unused swap slot */ 328 - if (!__swp_swapcount(entry)) 329 - return NULL; 327 + /* 328 + * Just skip read ahead for unused swap slot. 329 + * During swap_off when swap_slot_cache is disabled, 330 + * we have to handle the race between putting 331 + * swap entry in swap cache and marking swap slot 332 + * as SWAP_HAS_CACHE. That's done in later part of code or 333 + * else swap_off will be aborted if we return NULL. 334 + */ 335 + if (!__swp_swapcount(entry) && swap_slot_cache_enabled) 336 + break; 330 337 331 338 /* 332 339 * Get a new page to read into from swap.