aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>2009-06-16 18:32:52 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-16 22:47:42 -0400
commitcb4b86ba47bb0937b71fb825b3ed88adf7a190f0 (patch)
tree4b8528ba914a315e5857e7fe2a6e7d415f2e6650
parent6837765963f1723e80ca97b1fae660f3a60d77df (diff)
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: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Reviewed-by: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp> Acked-by: Balbir 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: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/swap.h7
-rw-r--r--mm/shmem.c2
-rw-r--r--mm/swap_state.c11
-rw-r--r--mm/swapfile.c19
-rw-r--r--mm/vmscan.c3
5 files changed, 33 insertions, 9 deletions
diff --git a/include/linux/swap.h b/include/linux/swap.h
index f30c06908f09..259e96c150ef 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -282,8 +282,10 @@ extern void si_swapinfo(struct sysinfo *);
282extern swp_entry_t get_swap_page(void); 282extern swp_entry_t get_swap_page(void);
283extern swp_entry_t get_swap_page_of_type(int); 283extern swp_entry_t get_swap_page_of_type(int);
284extern int swap_duplicate(swp_entry_t); 284extern int swap_duplicate(swp_entry_t);
285extern int swapcache_prepare(swp_entry_t);
285extern int valid_swaphandles(swp_entry_t, unsigned long *); 286extern int valid_swaphandles(swp_entry_t, unsigned long *);
286extern void swap_free(swp_entry_t); 287extern void swap_free(swp_entry_t);
288extern void swapcache_free(swp_entry_t, struct page *page);
287extern int free_swap_and_cache(swp_entry_t); 289extern int free_swap_and_cache(swp_entry_t);
288extern int swap_type_of(dev_t, sector_t, struct block_device **); 290extern int swap_type_of(dev_t, sector_t, struct block_device **);
289extern unsigned int count_swap_pages(int, int); 291extern unsigned int count_swap_pages(int, int);
@@ -352,11 +354,16 @@ static inline void show_swap_cache_info(void)
352 354
353#define free_swap_and_cache(swp) is_migration_entry(swp) 355#define free_swap_and_cache(swp) is_migration_entry(swp)
354#define swap_duplicate(swp) is_migration_entry(swp) 356#define swap_duplicate(swp) is_migration_entry(swp)
357#define swapcache_prepare(swp) is_migration_entry(swp)
355 358
356static inline void swap_free(swp_entry_t swp) 359static inline void swap_free(swp_entry_t swp)
357{ 360{
358} 361}
359 362
363static inline void swapcache_free(swp_entry_t swp, struct page *page)
364{
365}
366
360static inline struct page *swapin_readahead(swp_entry_t swp, gfp_t gfp_mask, 367static inline struct page *swapin_readahead(swp_entry_t swp, gfp_t gfp_mask,
361 struct vm_area_struct *vma, unsigned long addr) 368 struct vm_area_struct *vma, unsigned long addr)
362{ 369{
diff --git a/mm/shmem.c b/mm/shmem.c
index 0132fbd45a23..47ab19182287 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1097,7 +1097,7 @@ static int shmem_writepage(struct page *page, struct writeback_control *wbc)
1097 shmem_swp_unmap(entry); 1097 shmem_swp_unmap(entry);
1098unlock: 1098unlock:
1099 spin_unlock(&info->lock); 1099 spin_unlock(&info->lock);
1100 swap_free(swap); 1100 swapcache_free(swap, NULL);
1101redirty: 1101redirty:
1102 set_page_dirty(page); 1102 set_page_dirty(page);
1103 if (wbc->for_reclaim) 1103 if (wbc->for_reclaim)
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 1416e7e9e02d..19bdf3017a9e 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -162,11 +162,11 @@ int add_to_swap(struct page *page)
162 return 1; 162 return 1;
163 case -EEXIST: 163 case -EEXIST:
164 /* Raced with "speculative" read_swap_cache_async */ 164 /* Raced with "speculative" read_swap_cache_async */
165 swap_free(entry); 165 swapcache_free(entry, NULL);
166 continue; 166 continue;
167 default: 167 default:
168 /* -ENOMEM radix-tree allocation failure */ 168 /* -ENOMEM radix-tree allocation failure */
169 swap_free(entry); 169 swapcache_free(entry, NULL);
170 return 0; 170 return 0;
171 } 171 }
172 } 172 }
@@ -188,8 +188,7 @@ void delete_from_swap_cache(struct page *page)
188 __delete_from_swap_cache(page); 188 __delete_from_swap_cache(page);
189 spin_unlock_irq(&swapper_space.tree_lock); 189 spin_unlock_irq(&swapper_space.tree_lock);
190 190
191 mem_cgroup_uncharge_swapcache(page, entry); 191 swapcache_free(entry, page);
192 swap_free(entry);
193 page_cache_release(page); 192 page_cache_release(page);
194} 193}
195 194
@@ -293,7 +292,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
293 /* 292 /*
294 * Swap entry may have been freed since our caller observed it. 293 * Swap entry may have been freed since our caller observed it.
295 */ 294 */
296 if (!swap_duplicate(entry)) 295 if (!swapcache_prepare(entry))
297 break; 296 break;
298 297
299 /* 298 /*
@@ -317,7 +316,7 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
317 } 316 }
318 ClearPageSwapBacked(new_page); 317 ClearPageSwapBacked(new_page);
319 __clear_page_locked(new_page); 318 __clear_page_locked(new_page);
320 swap_free(entry); 319 swapcache_free(entry, NULL);
321 } while (err != -ENOMEM); 320 } while (err != -ENOMEM);
322 321
323 if (new_page) 322 if (new_page)
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 312fafe0ab6e..3187079903fd 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -510,6 +510,16 @@ void swap_free(swp_entry_t entry)
510} 510}
511 511
512/* 512/*
513 * Called after dropping swapcache to decrease refcnt to swap entries.
514 */
515void swapcache_free(swp_entry_t entry, struct page *page)
516{
517 if (page)
518 mem_cgroup_uncharge_swapcache(page, entry);
519 return swap_free(entry);
520}
521
522/*
513 * How many references to page are currently swapped out? 523 * How many references to page are currently swapped out?
514 */ 524 */
515static inline int page_swapcount(struct page *page) 525static inline int page_swapcount(struct page *page)
@@ -1979,6 +1989,15 @@ bad_file:
1979 goto out; 1989 goto out;
1980} 1990}
1981 1991
1992/*
1993 * Called when allocating swap cache for exising swap entry,
1994 */
1995int swapcache_prepare(swp_entry_t entry)
1996{
1997 return swap_duplicate(entry);
1998}
1999
2000
1982struct swap_info_struct * 2001struct swap_info_struct *
1983get_swap_info_struct(unsigned type) 2002get_swap_info_struct(unsigned type)
1984{ 2003{
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 2c4b945b011f..52339dd7bf85 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -470,8 +470,7 @@ static int __remove_mapping(struct address_space *mapping, struct page *page)
470 swp_entry_t swap = { .val = page_private(page) }; 470 swp_entry_t swap = { .val = page_private(page) };
471 __delete_from_swap_cache(page); 471 __delete_from_swap_cache(page);
472 spin_unlock_irq(&mapping->tree_lock); 472 spin_unlock_irq(&mapping->tree_lock);
473 mem_cgroup_uncharge_swapcache(page, swap); 473 swapcache_free(swap, page);
474 swap_free(swap);
475 } else { 474 } else {
476 __remove_from_page_cache(page); 475 __remove_from_page_cache(page);
477 spin_unlock_irq(&mapping->tree_lock); 476 spin_unlock_irq(&mapping->tree_lock);