Commit cb4b86ba authored by KAMEZAWA Hiroyuki's avatar KAMEZAWA Hiroyuki Committed by Linus Torvalds

mm: add swap cache interface for swap reference

In a following patch, the usage of swap cache is recorded into swap_map.
This patch is for necessary interface changes to do that.

2 interfaces:

  - swapcache_prepare()
  - swapcache_free()

are added for allocating/freeing refcnt from swap-cache to existing swap
entries.  But implementation itself is not changed under this patch.  At
adding swapcache_free(), memcg's hook code is moved under
swapcache_free().  This is better than using scattered hooks.
Signed-off-by: default avatarKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Reviewed-by: default avatarDaisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Acked-by: default avatarBalbir Singh <balbir@in.ibm.com>
Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Cc: Li Zefan <lizf@cn.fujitsu.com>
Cc: Dhaval Giani <dhaval@linux.vnet.ibm.com>
Cc: YAMAMOTO Takashi <yamamoto@valinux.co.jp>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 68377659
...@@ -282,8 +282,10 @@ extern void si_swapinfo(struct sysinfo *); ...@@ -282,8 +282,10 @@ extern void si_swapinfo(struct sysinfo *);
extern swp_entry_t get_swap_page(void); extern swp_entry_t get_swap_page(void);
extern swp_entry_t get_swap_page_of_type(int); extern swp_entry_t get_swap_page_of_type(int);
extern int swap_duplicate(swp_entry_t); extern int swap_duplicate(swp_entry_t);
extern int swapcache_prepare(swp_entry_t);
extern int valid_swaphandles(swp_entry_t, unsigned long *); extern int valid_swaphandles(swp_entry_t, unsigned long *);
extern void swap_free(swp_entry_t); extern void swap_free(swp_entry_t);
extern void swapcache_free(swp_entry_t, struct page *page);
extern int free_swap_and_cache(swp_entry_t); extern int free_swap_and_cache(swp_entry_t);
extern int swap_type_of(dev_t, sector_t, struct block_device **); extern int swap_type_of(dev_t, sector_t, struct block_device **);
extern unsigned int count_swap_pages(int, int); extern unsigned int count_swap_pages(int, int);
...@@ -352,11 +354,16 @@ static inline void show_swap_cache_info(void) ...@@ -352,11 +354,16 @@ static inline void show_swap_cache_info(void)
#define free_swap_and_cache(swp) is_migration_entry(swp) #define free_swap_and_cache(swp) is_migration_entry(swp)
#define swap_duplicate(swp) is_migration_entry(swp) #define swap_duplicate(swp) is_migration_entry(swp)
#define swapcache_prepare(swp) is_migration_entry(swp)
static inline void swap_free(swp_entry_t swp) static inline void swap_free(swp_entry_t swp)
{ {
} }
static inline void swapcache_free(swp_entry_t swp, struct page *page)
{
}
static inline struct page *swapin_readahead(swp_entry_t swp, gfp_t gfp_mask, static inline struct page *swapin_readahead(swp_entry_t swp, gfp_t gfp_mask,
struct vm_area_struct *vma, unsigned long addr) struct vm_area_struct *vma, unsigned long addr)
{ {
......
...@@ -1097,7 +1097,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc) ...@@ -1097,7 +1097,7 @@ 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);
swap_free(swap); swapcache_free(swap, NULL);
redirty: redirty:
set_page_dirty(page); set_page_dirty(page);
if (wbc->for_reclaim) if (wbc->for_reclaim)
......
...@@ -162,11 +162,11 @@ int add_to_swap(struct page *page) ...@@ -162,11 +162,11 @@ int add_to_swap(struct page *page)
return 1; return 1;
case -EEXIST: case -EEXIST:
/* Raced with "speculative" read_swap_cache_async */ /* Raced with "speculative" read_swap_cache_async */
swap_free(entry); swapcache_free(entry, NULL);
continue; continue;
default: default:
/* -ENOMEM radix-tree allocation failure */ /* -ENOMEM radix-tree allocation failure */
swap_free(entry); swapcache_free(entry, NULL);
return 0; return 0;
} }
} }
...@@ -188,8 +188,7 @@ void delete_from_swap_cache(struct page *page) ...@@ -188,8 +188,7 @@ void delete_from_swap_cache(struct page *page)
__delete_from_swap_cache(page); __delete_from_swap_cache(page);
spin_unlock_irq(&swapper_space.tree_lock); spin_unlock_irq(&swapper_space.tree_lock);
mem_cgroup_uncharge_swapcache(page, entry); swapcache_free(entry, page);
swap_free(entry);
page_cache_release(page); page_cache_release(page);
} }
...@@ -293,7 +292,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, ...@@ -293,7 +292,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
/* /*
* Swap entry may have been freed since our caller observed it. * Swap entry may have been freed since our caller observed it.
*/ */
if (!swap_duplicate(entry)) if (!swapcache_prepare(entry))
break; break;
/* /*
...@@ -317,7 +316,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask, ...@@ -317,7 +316,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
} }
ClearPageSwapBacked(new_page); ClearPageSwapBacked(new_page);
__clear_page_locked(new_page); __clear_page_locked(new_page);
swap_free(entry); swapcache_free(entry, NULL);
} while (err != -ENOMEM); } while (err != -ENOMEM);
if (new_page) if (new_page)
......
...@@ -509,6 +509,16 @@ void swap_free(swp_entry_t entry) ...@@ -509,6 +509,16 @@ void swap_free(swp_entry_t entry)
} }
} }
/*
* Called after dropping swapcache to decrease refcnt to swap entries.
*/
void swapcache_free(swp_entry_t entry, struct page *page)
{
if (page)
mem_cgroup_uncharge_swapcache(page, entry);
return swap_free(entry);
}
/* /*
* How many references to page are currently swapped out? * How many references to page are currently swapped out?
*/ */
...@@ -1979,6 +1989,15 @@ bad_file: ...@@ -1979,6 +1989,15 @@ bad_file:
goto out; goto out;
} }
/*
* Called when allocating swap cache for exising swap entry,
*/
int swapcache_prepare(swp_entry_t entry)
{
return swap_duplicate(entry);
}
struct swap_info_struct * struct swap_info_struct *
get_swap_info_struct(unsigned type) get_swap_info_struct(unsigned type)
{ {
......
...@@ -470,8 +470,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page) ...@@ -470,8 +470,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page)
swp_entry_t swap = { .val = page_private(page) }; swp_entry_t swap = { .val = page_private(page) };
__delete_from_swap_cache(page); __delete_from_swap_cache(page);
spin_unlock_irq(&mapping->tree_lock); spin_unlock_irq(&mapping->tree_lock);
mem_cgroup_uncharge_swapcache(page, swap); swapcache_free(swap, page);
swap_free(swap);
} else { } else {
__remove_from_page_cache(page); __remove_from_page_cache(page);
spin_unlock_irq(&mapping->tree_lock); spin_unlock_irq(&mapping->tree_lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment