aboutsummaryrefslogtreecommitdiffstats
path: root/mm/swap_state.c
diff options
context:
space:
mode:
authorShaohua Li <shli@kernel.org>2013-02-22 19:34:37 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-23 20:50:17 -0500
commit33806f06da654092182410d974b6d3c5396ea3eb (patch)
tree7f7da99d94481a1d4c78ebf05b410fc8ba654a39 /mm/swap_state.c
parent9800339b5e0f0e24ab3dac349e0de80d2018832e (diff)
swap: make each swap partition have one address_space
When I use several fast SSD to do swap, swapper_space.tree_lock is heavily contended. This makes each swap partition have one address_space to reduce the lock contention. There is an array of address_space for swap. The swap entry type is the index to the array. In my test with 3 SSD, this increases the swapout throughput 20%. [akpm@linux-foundation.org: revert unneeded change to __add_to_swap_cache] Signed-off-by: Shaohua Li <shli@fusionio.com> Cc: Hugh Dickins <hughd@google.com> Acked-by: Rik van Riel <riel@redhat.com> Acked-by: Minchan Kim <minchan@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/swap_state.c')
-rw-r--r--mm/swap_state.c55
1 files changed, 38 insertions, 17 deletions
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 0cb36fb1f61c..8d6644c5d0cc 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -36,12 +36,12 @@ static struct backing_dev_info swap_backing_dev_info = {
36 .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_SWAP_BACKED, 36 .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK | BDI_CAP_SWAP_BACKED,
37}; 37};
38 38
39struct address_space swapper_space = { 39struct address_space swapper_spaces[MAX_SWAPFILES] = {
40 .page_tree = RADIX_TREE_INIT(GFP_ATOMIC|__GFP_NOWARN), 40 [0 ... MAX_SWAPFILES - 1] = {
41 .tree_lock = __SPIN_LOCK_UNLOCKED(swapper_space.tree_lock), 41 .page_tree = RADIX_TREE_INIT(GFP_ATOMIC|__GFP_NOWARN),
42 .a_ops = &swap_aops, 42 .a_ops = &swap_aops,
43 .i_mmap_nonlinear = LIST_HEAD_INIT(swapper_space.i_mmap_nonlinear), 43 .backing_dev_info = &swap_backing_dev_info,
44 .backing_dev_info = &swap_backing_dev_info, 44 }
45}; 45};
46 46
47#define INC_CACHE_INFO(x) do { swap_cache_info.x++; } while (0) 47#define INC_CACHE_INFO(x) do { swap_cache_info.x++; } while (0)
@@ -53,9 +53,19 @@ static struct {
53 unsigned long find_total; 53 unsigned long find_total;
54} swap_cache_info; 54} swap_cache_info;
55 55
56unsigned long total_swapcache_pages(void)
57{
58 int i;
59 unsigned long ret = 0;
60
61 for (i = 0; i < MAX_SWAPFILES; i++)
62 ret += swapper_spaces[i].nrpages;
63 return ret;
64}
65
56void show_swap_cache_info(void) 66void show_swap_cache_info(void)
57{ 67{
58 printk("%lu pages in swap cache\n", total_swapcache_pages); 68 printk("%lu pages in swap cache\n", total_swapcache_pages());
59 printk("Swap cache stats: add %lu, delete %lu, find %lu/%lu\n", 69 printk("Swap cache stats: add %lu, delete %lu, find %lu/%lu\n",
60 swap_cache_info.add_total, swap_cache_info.del_total, 70 swap_cache_info.add_total, swap_cache_info.del_total,
61 swap_cache_info.find_success, swap_cache_info.find_total); 71 swap_cache_info.find_success, swap_cache_info.find_total);
@@ -70,6 +80,7 @@ void show_swap_cache_info(void)
70static int __add_to_swap_cache(struct page *page, swp_entry_t entry) 80static int __add_to_swap_cache(struct page *page, swp_entry_t entry)
71{ 81{
72 int error; 82 int error;
83 struct address_space *address_space;
73 84
74 VM_BUG_ON(!PageLocked(page)); 85 VM_BUG_ON(!PageLocked(page));
75 VM_BUG_ON(PageSwapCache(page)); 86 VM_BUG_ON(PageSwapCache(page));
@@ -79,14 +90,16 @@ static int __add_to_swap_cache(struct page *page, swp_entry_t entry)
79 SetPageSwapCache(page); 90 SetPageSwapCache(page);
80 set_page_private(page, entry.val); 91 set_page_private(page, entry.val);
81 92
82 spin_lock_irq(&swapper_space.tree_lock); 93 address_space = swap_address_space(entry);
83 error = radix_tree_insert(&swapper_space.page_tree, entry.val, page); 94 spin_lock_irq(&address_space->tree_lock);
95 error = radix_tree_insert(&address_space->page_tree,
96 entry.val, page);
84 if (likely(!error)) { 97 if (likely(!error)) {
85 total_swapcache_pages++; 98 address_space->nrpages++;
86 __inc_zone_page_state(page, NR_FILE_PAGES); 99 __inc_zone_page_state(page, NR_FILE_PAGES);
87 INC_CACHE_INFO(add_total); 100 INC_CACHE_INFO(add_total);
88 } 101 }
89 spin_unlock_irq(&swapper_space.tree_lock); 102 spin_unlock_irq(&address_space->tree_lock);
90 103
91 if (unlikely(error)) { 104 if (unlikely(error)) {
92 /* 105 /*
@@ -122,14 +135,19 @@ int add_to_swap_cache(struct page *page, swp_entry_t entry, gfp_t gfp_mask)
122 */ 135 */
123void __delete_from_swap_cache(struct page *page) 136void __delete_from_swap_cache(struct page *page)
124{ 137{
138 swp_entry_t entry;
139 struct address_space *address_space;
140
125 VM_BUG_ON(!PageLocked(page)); 141 VM_BUG_ON(!PageLocked(page));
126 VM_BUG_ON(!PageSwapCache(page)); 142 VM_BUG_ON(!PageSwapCache(page));
127 VM_BUG_ON(PageWriteback(page)); 143 VM_BUG_ON(PageWriteback(page));
128 144
129 radix_tree_delete(&swapper_space.page_tree, page_private(page)); 145 entry.val = page_private(page);
146 address_space = swap_address_space(entry);
147 radix_tree_delete(&address_space->page_tree, page_private(page));
130 set_page_private(page, 0); 148 set_page_private(page, 0);
131 ClearPageSwapCache(page); 149 ClearPageSwapCache(page);
132 total_swapcache_pages--; 150 address_space->nrpages--;
133 __dec_zone_page_state(page, NR_FILE_PAGES); 151 __dec_zone_page_state(page, NR_FILE_PAGES);
134 INC_CACHE_INFO(del_total); 152 INC_CACHE_INFO(del_total);
135} 153}
@@ -195,12 +213,14 @@ int add_to_swap(struct page *page)
195void delete_from_swap_cache(struct page *page) 213void delete_from_swap_cache(struct page *page)
196{ 214{
197 swp_entry_t entry; 215 swp_entry_t entry;
216 struct address_space *address_space;
198 217
199 entry.val = page_private(page); 218 entry.val = page_private(page);
200 219
201 spin_lock_irq(&swapper_space.tree_lock); 220 address_space = swap_address_space(entry);
221 spin_lock_irq(&address_space->tree_lock);
202 __delete_from_swap_cache(page); 222 __delete_from_swap_cache(page);
203 spin_unlock_irq(&swapper_space.tree_lock); 223 spin_unlock_irq(&address_space->tree_lock);
204 224
205 swapcache_free(entry, page); 225 swapcache_free(entry, page);
206 page_cache_release(page); 226 page_cache_release(page);
@@ -263,7 +283,7 @@ struct page * lookup_swap_cache(swp_entry_t entry)
263{ 283{
264 struct page *page; 284 struct page *page;
265 285
266 page = find_get_page(&swapper_space, entry.val); 286 page = find_get_page(swap_address_space(entry), entry.val);
267 287
268 if (page) 288 if (page)
269 INC_CACHE_INFO(find_success); 289 INC_CACHE_INFO(find_success);
@@ -290,7 +310,8 @@ struct page *read_swap_cache_async(swp_entry_t entry, gfp_t gfp_mask,
290 * called after lookup_swap_cache() failed, re-calling 310 * called after lookup_swap_cache() failed, re-calling
291 * that would confuse statistics. 311 * that would confuse statistics.
292 */ 312 */
293 found_page = find_get_page(&swapper_space, entry.val); 313 found_page = find_get_page(swap_address_space(entry),
314 entry.val);
294 if (found_page) 315 if (found_page)
295 break; 316 break;
296 317