mm: add_to_swap_cache() does not return -EEXIST

After commit 355cfa73 ("mm: modify swap_map and add SWAP_HAS_CACHE flag"),
only the context which have set SWAP_HAS_CACHE flag by swapcache_prepare()
or get_swap_page() would call add_to_swap_cache().  So add_to_swap_cache()
doesn't return -EEXIST any more.

Even though it doesn't return -EEXIST, it's not good behavior conceptually
to call swapcache_prepare() in the -EEXIST case, because it means clearing
SWAP_HAS_CACHE flag while the entry is on swap cache.

This patch removes redundant codes and comments from callers of it, and
adds VM_BUG_ON() in error path of add_to_swap_cache() and some comments.

Signed-off-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Reviewed-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Balbir Singh <balbir@linux.vnet.ibm.com>
Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Daisuke Nishimura 2009-09-21 17:02:52 -07:00 committed by Linus Torvalds
parent 31a5639623
commit 2ca4532a49
2 changed files with 41 additions and 38 deletions

View File

@ -1097,6 +1097,10 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
shmem_swp_unmap(entry); shmem_swp_unmap(entry);
unlock: unlock:
spin_unlock(&info->lock); spin_unlock(&info->lock);
/*
* add_to_swap_cache() doesn't return -EEXIST, so we can safely
* clear SWAP_HAS_CACHE flag.
*/
swapcache_free(swap, NULL); swapcache_free(swap, NULL);
redirty: redirty:
set_page_dirty(page); set_page_dirty(page);

View File

@ -92,6 +92,12 @@ static int __add_to_swap_cache(struct page *page, swp_entry_t entry)
spin_unlock_irq(&swapper_space.tree_lock); spin_unlock_irq(&swapper_space.tree_lock);
if (unlikely(error)) { if (unlikely(error)) {
/*
* Only the context which have set SWAP_HAS_CACHE flag
* would call add_to_swap_cache().
* So add_to_swap_cache() doesn't returns -EEXIST.
*/
VM_BUG_ON(error == -EEXIST);
set_page_private(page, 0UL); set_page_private(page, 0UL);
ClearPageSwapCache(page); ClearPageSwapCache(page);
page_cache_release(page); page_cache_release(page);
@ -146,38 +152,34 @@ int add_to_swap(struct page *page)
VM_BUG_ON(!PageLocked(page)); VM_BUG_ON(!PageLocked(page));
VM_BUG_ON(!PageUptodate(page)); VM_BUG_ON(!PageUptodate(page));
for (;;) { entry = get_swap_page();
entry = get_swap_page(); if (!entry.val)
if (!entry.val) return 0;
return 0;
/* /*
* Radix-tree node allocations from PF_MEMALLOC contexts could * Radix-tree node allocations from PF_MEMALLOC contexts could
* completely exhaust the page allocator. __GFP_NOMEMALLOC * completely exhaust the page allocator. __GFP_NOMEMALLOC
* stops emergency reserves from being allocated. * stops emergency reserves from being allocated.
* *
* TODO: this could cause a theoretical memory reclaim * TODO: this could cause a theoretical memory reclaim
* deadlock in the swap out path. * deadlock in the swap out path.
*/ */
/* /*
* Add it to the swap cache and mark it dirty * Add it to the swap cache and mark it dirty
*/ */
err = add_to_swap_cache(page, entry, err = add_to_swap_cache(page, entry,
__GFP_HIGH|__GFP_NOMEMALLOC|__GFP_NOWARN); __GFP_HIGH|__GFP_NOMEMALLOC|__GFP_NOWARN);
switch (err) { if (!err) { /* Success */
case 0: /* Success */ SetPageDirty(page);
SetPageDirty(page); return 1;
return 1; } else { /* -ENOMEM radix-tree allocation failure */
case -EEXIST: /*
/* Raced with "speculative" read_swap_cache_async */ * add_to_swap_cache() doesn't return -EEXIST, so we can safely
swapcache_free(entry, NULL); * clear SWAP_HAS_CACHE flag.
continue; */
default: swapcache_free(entry, NULL);
/* -ENOMEM radix-tree allocation failure */ return 0;
swapcache_free(entry, NULL);
return 0;
}
} }
} }
@ -318,14 +320,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
break; break;
} }
/* /* May fail (-ENOMEM) if radix-tree node allocation failed. */
* Associate the page with swap entry in the swap cache.
* May fail (-EEXIST) if there is already a page associated
* with this entry in the swap cache: added by a racing
* read_swap_cache_async, or add_to_swap or shmem_writepage
* re-using the just freed swap entry for an existing page.
* May fail (-ENOMEM) if radix-tree node allocation failed.
*/
__set_page_locked(new_page); __set_page_locked(new_page);
SetPageSwapBacked(new_page); SetPageSwapBacked(new_page);
err = __add_to_swap_cache(new_page, entry); err = __add_to_swap_cache(new_page, entry);
@ -341,6 +336,10 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
radix_tree_preload_end(); radix_tree_preload_end();
ClearPageSwapBacked(new_page); ClearPageSwapBacked(new_page);
__clear_page_locked(new_page); __clear_page_locked(new_page);
/*
* add_to_swap_cache() doesn't return -EEXIST, so we can safely
* clear SWAP_HAS_CACHE flag.
*/
swapcache_free(entry, NULL); swapcache_free(entry, NULL);
} while (err != -ENOMEM); } while (err != -ENOMEM);