Skip to content

Commit

Permalink
mm: add_to_swap_cache() does not return -EEXIST
Browse files Browse the repository at this point in the history
After commit 355cfa7 ("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 <[email protected]>
Reviewed-by: KAMEZAWA Hiroyuki <[email protected]>
Cc: Balbir Singh <[email protected]>
Cc: Hugh Dickins <[email protected]>
Cc: Johannes Weiner <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Daisuke Nishimura authored and torvalds committed Sep 22, 2009
1 parent 31a5639 commit 2ca4532
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 37 deletions.
4 changes: 4 additions & 0 deletions mm/shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -1097,6 +1097,10 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
shmem_swp_unmap(entry);
unlock:
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);
redirty:
set_page_dirty(page);
Expand Down
73 changes: 36 additions & 37 deletions mm/swap_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ static int __add_to_swap_cache(struct page *page, swp_entry_t entry)
spin_unlock_irq(&swapper_space.tree_lock);

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);
ClearPageSwapCache(page);
page_cache_release(page);
Expand Down Expand Up @@ -146,38 +152,34 @@ int add_to_swap(struct page *page)
VM_BUG_ON(!PageLocked(page));
VM_BUG_ON(!PageUptodate(page));

for (;;) {
entry = get_swap_page();
if (!entry.val)
return 0;
entry = get_swap_page();
if (!entry.val)
return 0;

/*
* Radix-tree node allocations from PF_MEMALLOC contexts could
* completely exhaust the page allocator. __GFP_NOMEMALLOC
* stops emergency reserves from being allocated.
*
* TODO: this could cause a theoretical memory reclaim
* deadlock in the swap out path.
*/
/*
* Add it to the swap cache and mark it dirty
*/
err = add_to_swap_cache(page, entry,
__GFP_HIGH|__GFP_NOMEMALLOC|__GFP_NOWARN);

if (!err) { /* Success */
SetPageDirty(page);
return 1;
} else { /* -ENOMEM radix-tree allocation failure */
/*
* Radix-tree node allocations from PF_MEMALLOC contexts could
* completely exhaust the page allocator. __GFP_NOMEMALLOC
* stops emergency reserves from being allocated.
*
* TODO: this could cause a theoretical memory reclaim
* deadlock in the swap out path.
*/
/*
* Add it to the swap cache and mark it dirty
* add_to_swap_cache() doesn't return -EEXIST, so we can safely
* clear SWAP_HAS_CACHE flag.
*/
err = add_to_swap_cache(page, entry,
__GFP_HIGH|__GFP_NOMEMALLOC|__GFP_NOWARN);

switch (err) {
case 0: /* Success */
SetPageDirty(page);
return 1;
case -EEXIST:
/* Raced with "speculative" read_swap_cache_async */
swapcache_free(entry, NULL);
continue;
default:
/* -ENOMEM radix-tree allocation failure */
swapcache_free(entry, NULL);
return 0;
}
swapcache_free(entry, NULL);
return 0;
}
}

Expand Down Expand Up @@ -318,14 +320,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
break;
}

/*
* 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.
*/
/* May fail (-ENOMEM) if radix-tree node allocation failed. */
__set_page_locked(new_page);
SetPageSwapBacked(new_page);
err = __add_to_swap_cache(new_page, entry);
Expand All @@ -341,6 +336,10 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
radix_tree_preload_end();
ClearPageSwapBacked(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);
} while (err != -ENOMEM);

Expand Down

0 comments on commit 2ca4532

Please sign in to comment.