diff options
Diffstat (limited to 'mm/swap_state.c')
-rw-r--r-- | mm/swap_state.c | 18 |
1 files changed, 17 insertions, 1 deletions
diff --git a/mm/swap_state.c b/mm/swap_state.c index b3d40dcf3624..f24ab0dff554 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c | |||
@@ -336,8 +336,24 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, | |||
336 | * Swap entry may have been freed since our caller observed it. | 336 | * Swap entry may have been freed since our caller observed it. |
337 | */ | 337 | */ |
338 | err = swapcache_prepare(entry); | 338 | err = swapcache_prepare(entry); |
339 | if (err == -EEXIST) { /* seems racy */ | 339 | if (err == -EEXIST) { |
340 | radix_tree_preload_end(); | 340 | radix_tree_preload_end(); |
341 | /* | ||
342 | * We might race against get_swap_page() and stumble | ||
343 | * across a SWAP_HAS_CACHE swap_map entry whose page | ||
344 | * has not been brought into the swapcache yet, while | ||
345 | * the other end is scheduled away waiting on discard | ||
346 | * I/O completion at scan_swap_map(). | ||
347 | * | ||
348 | * In order to avoid turning this transitory state | ||
349 | * into a permanent loop around this -EEXIST case | ||
350 | * if !CONFIG_PREEMPT and the I/O completion happens | ||
351 | * to be waiting on the CPU waitqueue where we are now | ||
352 | * busy looping, we just conditionally invoke the | ||
353 | * scheduler here, if there are some more important | ||
354 | * tasks to run. | ||
355 | */ | ||
356 | cond_resched(); | ||
341 | continue; | 357 | continue; |
342 | } | 358 | } |
343 | if (err) { /* swp entry is obsolete ? */ | 359 | if (err) { /* swp entry is obsolete ? */ |