diff options
author | Hugh Dickins <hughd@google.com> | 2013-02-22 19:36:12 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-23 20:50:24 -0500 |
commit | ef53d16cded7f89b3843b7a96970dab897843ea5 (patch) | |
tree | 3098af6a91b088212acb5c459ee9af1488cfdfe1 /mm/ksm.c | |
parent | 56f31801ccdecb420d0d1fd2bf9f337c355214a9 (diff) |
ksm: allocate roots when needed
It is a pity to have MAX_NUMNODES+MAX_NUMNODES tree roots statically
allocated, particularly when very few users will ever actually tune
merge_across_nodes 0 to use more than 1+1 of those trees. Not a big
deal (only 16kB wasted on each machine with CONFIG_MAXSMP), but a pity.
Start off with 1+1 statically allocated, then if merge_across_nodes is
ever tuned, allocate for nr_node_ids+nr_node_ids. Do not attempt to
free up the extra if it's tuned back, that would be a waste of effort.
Signed-off-by: Hugh Dickins <hughd@google.com>
Cc: Mel Gorman <mgorman@suse.de>
Cc: Petr Holasek <pholasek@redhat.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: Izik Eidus <izik.eidus@ravellosystems.com>
Cc: Johannes Weiner <hannes@cmpxchg.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/ksm.c')
-rw-r--r-- | mm/ksm.c | 72 |
1 files changed, 49 insertions, 23 deletions
@@ -183,8 +183,10 @@ struct rmap_item { | |||
183 | #define STABLE_FLAG 0x200 /* is listed from the stable tree */ | 183 | #define STABLE_FLAG 0x200 /* is listed from the stable tree */ |
184 | 184 | ||
185 | /* The stable and unstable tree heads */ | 185 | /* The stable and unstable tree heads */ |
186 | static struct rb_root root_unstable_tree[MAX_NUMNODES]; | 186 | static struct rb_root one_stable_tree[1] = { RB_ROOT }; |
187 | static struct rb_root root_stable_tree[MAX_NUMNODES]; | 187 | static struct rb_root one_unstable_tree[1] = { RB_ROOT }; |
188 | static struct rb_root *root_stable_tree = one_stable_tree; | ||
189 | static struct rb_root *root_unstable_tree = one_unstable_tree; | ||
188 | 190 | ||
189 | /* Recently migrated nodes of stable tree, pending proper placement */ | 191 | /* Recently migrated nodes of stable tree, pending proper placement */ |
190 | static LIST_HEAD(migrate_nodes); | 192 | static LIST_HEAD(migrate_nodes); |
@@ -224,8 +226,10 @@ static unsigned int ksm_thread_sleep_millisecs = 20; | |||
224 | #ifdef CONFIG_NUMA | 226 | #ifdef CONFIG_NUMA |
225 | /* Zeroed when merging across nodes is not allowed */ | 227 | /* Zeroed when merging across nodes is not allowed */ |
226 | static unsigned int ksm_merge_across_nodes = 1; | 228 | static unsigned int ksm_merge_across_nodes = 1; |
229 | static int ksm_nr_node_ids = 1; | ||
227 | #else | 230 | #else |
228 | #define ksm_merge_across_nodes 1U | 231 | #define ksm_merge_across_nodes 1U |
232 | #define ksm_nr_node_ids 1 | ||
229 | #endif | 233 | #endif |
230 | 234 | ||
231 | #define KSM_RUN_STOP 0 | 235 | #define KSM_RUN_STOP 0 |
@@ -508,7 +512,7 @@ static void remove_node_from_stable_tree(struct stable_node *stable_node) | |||
508 | list_del(&stable_node->list); | 512 | list_del(&stable_node->list); |
509 | else | 513 | else |
510 | rb_erase(&stable_node->node, | 514 | rb_erase(&stable_node->node, |
511 | &root_stable_tree[NUMA(stable_node->nid)]); | 515 | root_stable_tree + NUMA(stable_node->nid)); |
512 | free_stable_node(stable_node); | 516 | free_stable_node(stable_node); |
513 | } | 517 | } |
514 | 518 | ||
@@ -644,7 +648,7 @@ static void remove_rmap_item_from_tree(struct rmap_item *rmap_item) | |||
644 | BUG_ON(age > 1); | 648 | BUG_ON(age > 1); |
645 | if (!age) | 649 | if (!age) |
646 | rb_erase(&rmap_item->node, | 650 | rb_erase(&rmap_item->node, |
647 | &root_unstable_tree[NUMA(rmap_item->nid)]); | 651 | root_unstable_tree + NUMA(rmap_item->nid)); |
648 | ksm_pages_unshared--; | 652 | ksm_pages_unshared--; |
649 | rmap_item->address &= PAGE_MASK; | 653 | rmap_item->address &= PAGE_MASK; |
650 | } | 654 | } |
@@ -742,7 +746,7 @@ static int remove_all_stable_nodes(void) | |||
742 | int nid; | 746 | int nid; |
743 | int err = 0; | 747 | int err = 0; |
744 | 748 | ||
745 | for (nid = 0; nid < nr_node_ids; nid++) { | 749 | for (nid = 0; nid < ksm_nr_node_ids; nid++) { |
746 | while (root_stable_tree[nid].rb_node) { | 750 | while (root_stable_tree[nid].rb_node) { |
747 | stable_node = rb_entry(root_stable_tree[nid].rb_node, | 751 | stable_node = rb_entry(root_stable_tree[nid].rb_node, |
748 | struct stable_node, node); | 752 | struct stable_node, node); |
@@ -1150,6 +1154,7 @@ static struct page *try_to_merge_two_pages(struct rmap_item *rmap_item, | |||
1150 | static struct page *stable_tree_search(struct page *page) | 1154 | static struct page *stable_tree_search(struct page *page) |
1151 | { | 1155 | { |
1152 | int nid; | 1156 | int nid; |
1157 | struct rb_root *root; | ||
1153 | struct rb_node **new; | 1158 | struct rb_node **new; |
1154 | struct rb_node *parent; | 1159 | struct rb_node *parent; |
1155 | struct stable_node *stable_node; | 1160 | struct stable_node *stable_node; |
@@ -1163,8 +1168,9 @@ static struct page *stable_tree_search(struct page *page) | |||
1163 | } | 1168 | } |
1164 | 1169 | ||
1165 | nid = get_kpfn_nid(page_to_pfn(page)); | 1170 | nid = get_kpfn_nid(page_to_pfn(page)); |
1171 | root = root_stable_tree + nid; | ||
1166 | again: | 1172 | again: |
1167 | new = &root_stable_tree[nid].rb_node; | 1173 | new = &root->rb_node; |
1168 | parent = NULL; | 1174 | parent = NULL; |
1169 | 1175 | ||
1170 | while (*new) { | 1176 | while (*new) { |
@@ -1219,7 +1225,7 @@ again: | |||
1219 | list_del(&page_node->list); | 1225 | list_del(&page_node->list); |
1220 | DO_NUMA(page_node->nid = nid); | 1226 | DO_NUMA(page_node->nid = nid); |
1221 | rb_link_node(&page_node->node, parent, new); | 1227 | rb_link_node(&page_node->node, parent, new); |
1222 | rb_insert_color(&page_node->node, &root_stable_tree[nid]); | 1228 | rb_insert_color(&page_node->node, root); |
1223 | get_page(page); | 1229 | get_page(page); |
1224 | return page; | 1230 | return page; |
1225 | 1231 | ||
@@ -1227,11 +1233,10 @@ replace: | |||
1227 | if (page_node) { | 1233 | if (page_node) { |
1228 | list_del(&page_node->list); | 1234 | list_del(&page_node->list); |
1229 | DO_NUMA(page_node->nid = nid); | 1235 | DO_NUMA(page_node->nid = nid); |
1230 | rb_replace_node(&stable_node->node, | 1236 | rb_replace_node(&stable_node->node, &page_node->node, root); |
1231 | &page_node->node, &root_stable_tree[nid]); | ||
1232 | get_page(page); | 1237 | get_page(page); |
1233 | } else { | 1238 | } else { |
1234 | rb_erase(&stable_node->node, &root_stable_tree[nid]); | 1239 | rb_erase(&stable_node->node, root); |
1235 | page = NULL; | 1240 | page = NULL; |
1236 | } | 1241 | } |
1237 | stable_node->head = &migrate_nodes; | 1242 | stable_node->head = &migrate_nodes; |
@@ -1250,13 +1255,15 @@ static struct stable_node *stable_tree_insert(struct page *kpage) | |||
1250 | { | 1255 | { |
1251 | int nid; | 1256 | int nid; |
1252 | unsigned long kpfn; | 1257 | unsigned long kpfn; |
1258 | struct rb_root *root; | ||
1253 | struct rb_node **new; | 1259 | struct rb_node **new; |
1254 | struct rb_node *parent = NULL; | 1260 | struct rb_node *parent = NULL; |
1255 | struct stable_node *stable_node; | 1261 | struct stable_node *stable_node; |
1256 | 1262 | ||
1257 | kpfn = page_to_pfn(kpage); | 1263 | kpfn = page_to_pfn(kpage); |
1258 | nid = get_kpfn_nid(kpfn); | 1264 | nid = get_kpfn_nid(kpfn); |
1259 | new = &root_stable_tree[nid].rb_node; | 1265 | root = root_stable_tree + nid; |
1266 | new = &root->rb_node; | ||
1260 | 1267 | ||
1261 | while (*new) { | 1268 | while (*new) { |
1262 | struct page *tree_page; | 1269 | struct page *tree_page; |
@@ -1295,7 +1302,7 @@ static struct stable_node *stable_tree_insert(struct page *kpage) | |||
1295 | set_page_stable_node(kpage, stable_node); | 1302 | set_page_stable_node(kpage, stable_node); |
1296 | DO_NUMA(stable_node->nid = nid); | 1303 | DO_NUMA(stable_node->nid = nid); |
1297 | rb_link_node(&stable_node->node, parent, new); | 1304 | rb_link_node(&stable_node->node, parent, new); |
1298 | rb_insert_color(&stable_node->node, &root_stable_tree[nid]); | 1305 | rb_insert_color(&stable_node->node, root); |
1299 | 1306 | ||
1300 | return stable_node; | 1307 | return stable_node; |
1301 | } | 1308 | } |
@@ -1325,7 +1332,7 @@ struct rmap_item *unstable_tree_search_insert(struct rmap_item *rmap_item, | |||
1325 | int nid; | 1332 | int nid; |
1326 | 1333 | ||
1327 | nid = get_kpfn_nid(page_to_pfn(page)); | 1334 | nid = get_kpfn_nid(page_to_pfn(page)); |
1328 | root = &root_unstable_tree[nid]; | 1335 | root = root_unstable_tree + nid; |
1329 | new = &root->rb_node; | 1336 | new = &root->rb_node; |
1330 | 1337 | ||
1331 | while (*new) { | 1338 | while (*new) { |
@@ -1422,7 +1429,7 @@ static void cmp_and_merge_page(struct page *page, struct rmap_item *rmap_item) | |||
1422 | if (stable_node->head != &migrate_nodes && | 1429 | if (stable_node->head != &migrate_nodes && |
1423 | get_kpfn_nid(stable_node->kpfn) != NUMA(stable_node->nid)) { | 1430 | get_kpfn_nid(stable_node->kpfn) != NUMA(stable_node->nid)) { |
1424 | rb_erase(&stable_node->node, | 1431 | rb_erase(&stable_node->node, |
1425 | &root_stable_tree[NUMA(stable_node->nid)]); | 1432 | root_stable_tree + NUMA(stable_node->nid)); |
1426 | stable_node->head = &migrate_nodes; | 1433 | stable_node->head = &migrate_nodes; |
1427 | list_add(&stable_node->list, stable_node->head); | 1434 | list_add(&stable_node->list, stable_node->head); |
1428 | } | 1435 | } |
@@ -1574,7 +1581,7 @@ static struct rmap_item *scan_get_next_rmap_item(struct page **page) | |||
1574 | } | 1581 | } |
1575 | } | 1582 | } |
1576 | 1583 | ||
1577 | for (nid = 0; nid < nr_node_ids; nid++) | 1584 | for (nid = 0; nid < ksm_nr_node_ids; nid++) |
1578 | root_unstable_tree[nid] = RB_ROOT; | 1585 | root_unstable_tree[nid] = RB_ROOT; |
1579 | 1586 | ||
1580 | spin_lock(&ksm_mmlist_lock); | 1587 | spin_lock(&ksm_mmlist_lock); |
@@ -2094,8 +2101,8 @@ static void ksm_check_stable_tree(unsigned long start_pfn, | |||
2094 | struct rb_node *node; | 2101 | struct rb_node *node; |
2095 | int nid; | 2102 | int nid; |
2096 | 2103 | ||
2097 | for (nid = 0; nid < nr_node_ids; nid++) { | 2104 | for (nid = 0; nid < ksm_nr_node_ids; nid++) { |
2098 | node = rb_first(&root_stable_tree[nid]); | 2105 | node = rb_first(root_stable_tree + nid); |
2099 | while (node) { | 2106 | while (node) { |
2100 | stable_node = rb_entry(node, struct stable_node, node); | 2107 | stable_node = rb_entry(node, struct stable_node, node); |
2101 | if (stable_node->kpfn >= start_pfn && | 2108 | if (stable_node->kpfn >= start_pfn && |
@@ -2105,7 +2112,7 @@ static void ksm_check_stable_tree(unsigned long start_pfn, | |||
2105 | * which is why we keep kpfn instead of page* | 2112 | * which is why we keep kpfn instead of page* |
2106 | */ | 2113 | */ |
2107 | remove_node_from_stable_tree(stable_node); | 2114 | remove_node_from_stable_tree(stable_node); |
2108 | node = rb_first(&root_stable_tree[nid]); | 2115 | node = rb_first(root_stable_tree + nid); |
2109 | } else | 2116 | } else |
2110 | node = rb_next(node); | 2117 | node = rb_next(node); |
2111 | cond_resched(); | 2118 | cond_resched(); |
@@ -2298,8 +2305,31 @@ static ssize_t merge_across_nodes_store(struct kobject *kobj, | |||
2298 | if (ksm_merge_across_nodes != knob) { | 2305 | if (ksm_merge_across_nodes != knob) { |
2299 | if (ksm_pages_shared || remove_all_stable_nodes()) | 2306 | if (ksm_pages_shared || remove_all_stable_nodes()) |
2300 | err = -EBUSY; | 2307 | err = -EBUSY; |
2301 | else | 2308 | else if (root_stable_tree == one_stable_tree) { |
2309 | struct rb_root *buf; | ||
2310 | /* | ||
2311 | * This is the first time that we switch away from the | ||
2312 | * default of merging across nodes: must now allocate | ||
2313 | * a buffer to hold as many roots as may be needed. | ||
2314 | * Allocate stable and unstable together: | ||
2315 | * MAXSMP NODES_SHIFT 10 will use 16kB. | ||
2316 | */ | ||
2317 | buf = kcalloc(nr_node_ids + nr_node_ids, | ||
2318 | sizeof(*buf), GFP_KERNEL | __GFP_ZERO); | ||
2319 | /* Let us assume that RB_ROOT is NULL is zero */ | ||
2320 | if (!buf) | ||
2321 | err = -ENOMEM; | ||
2322 | else { | ||
2323 | root_stable_tree = buf; | ||
2324 | root_unstable_tree = buf + nr_node_ids; | ||
2325 | /* Stable tree is empty but not the unstable */ | ||
2326 | root_unstable_tree[0] = one_unstable_tree[0]; | ||
2327 | } | ||
2328 | } | ||
2329 | if (!err) { | ||
2302 | ksm_merge_across_nodes = knob; | 2330 | ksm_merge_across_nodes = knob; |
2331 | ksm_nr_node_ids = knob ? 1 : nr_node_ids; | ||
2332 | } | ||
2303 | } | 2333 | } |
2304 | mutex_unlock(&ksm_thread_mutex); | 2334 | mutex_unlock(&ksm_thread_mutex); |
2305 | 2335 | ||
@@ -2378,15 +2408,11 @@ static int __init ksm_init(void) | |||
2378 | { | 2408 | { |
2379 | struct task_struct *ksm_thread; | 2409 | struct task_struct *ksm_thread; |
2380 | int err; | 2410 | int err; |
2381 | int nid; | ||
2382 | 2411 | ||
2383 | err = ksm_slab_init(); | 2412 | err = ksm_slab_init(); |
2384 | if (err) | 2413 | if (err) |
2385 | goto out; | 2414 | goto out; |
2386 | 2415 | ||
2387 | for (nid = 0; nid < nr_node_ids; nid++) | ||
2388 | root_stable_tree[nid] = RB_ROOT; | ||
2389 | |||
2390 | ksm_thread = kthread_run(ksm_scan_thread, NULL, "ksmd"); | 2416 | ksm_thread = kthread_run(ksm_scan_thread, NULL, "ksmd"); |
2391 | if (IS_ERR(ksm_thread)) { | 2417 | if (IS_ERR(ksm_thread)) { |
2392 | printk(KERN_ERR "ksm: creating kthread failed\n"); | 2418 | printk(KERN_ERR "ksm: creating kthread failed\n"); |