summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorUladzislau Rezki (Sony) <urezki@gmail.com>2019-09-23 18:36:36 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-09-24 18:54:10 -0400
commitdd3b8353bae79395b12a178de057b183ff0122eb (patch)
treed62e86f82d0d18342e4e8d6a0443e0304d7303a5
parent5ed867037eb1f15b7e8cc92497671fd4b3864e4a (diff)
mm/vmalloc: do not keep unpurged areas in the busy tree
The busy tree can be quite big, even though the area is freed or unmapped it still stays there until "purge" logic removes it. 1) Optimize and reduce the size of "busy" tree by removing a node from it right away as soon as user triggers free paths. It is possible to do so, because the allocation is done using another augmented tree. The vmalloc test driver shows the difference, for example the "fix_size_alloc_test" is ~11% better comparing with default configuration: sudo ./test_vmalloc.sh performance <default> Summary: fix_size_alloc_test loops: 1000000 avg: 993985 usec Summary: full_fit_alloc_test loops: 1000000 avg: 973554 usec Summary: long_busy_list_alloc_test loops: 1000000 avg: 12617652 usec <default> <this patch> Summary: fix_size_alloc_test loops: 1000000 avg: 882263 usec Summary: full_fit_alloc_test loops: 1000000 avg: 973407 usec Summary: long_busy_list_alloc_test loops: 1000000 avg: 12593929 usec <this patch> 2) Since the busy tree now contains allocated areas only and does not interfere with lazily free nodes, introduce the new function show_purge_info() that dumps "unpurged" areas that is propagated through "/proc/vmallocinfo". 3) Eliminate VM_LAZY_FREE flag. Link: http://lkml.kernel.org/r/20190716152656.12255-2-lpf.vector@gmail.com Signed-off-by: Uladzislau Rezki (Sony) <urezki@gmail.com> Signed-off-by: Pengfei Li <lpf.vector@gmail.com> Cc: Roman Gushchin <guro@fb.com> Cc: Uladzislau Rezki <urezki@gmail.com> Cc: Hillf Danton <hdanton@sina.com> Cc: Michal Hocko <mhocko@suse.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: Oleksiy Avramchenko <oleksiy.avramchenko@sonymobile.com> Cc: Steven Rostedt <rostedt@goodmis.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/vmalloc.c52
1 files changed, 44 insertions, 8 deletions
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index c1246d77cf75..d535ef125bda 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -329,7 +329,6 @@ EXPORT_SYMBOL(vmalloc_to_pfn);
329#define DEBUG_AUGMENT_PROPAGATE_CHECK 0 329#define DEBUG_AUGMENT_PROPAGATE_CHECK 0
330#define DEBUG_AUGMENT_LOWEST_MATCH_CHECK 0 330#define DEBUG_AUGMENT_LOWEST_MATCH_CHECK 0
331 331
332#define VM_LAZY_FREE 0x02
333#define VM_VM_AREA 0x04 332#define VM_VM_AREA 0x04
334 333
335static DEFINE_SPINLOCK(vmap_area_lock); 334static DEFINE_SPINLOCK(vmap_area_lock);
@@ -1282,7 +1281,14 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)
1282 llist_for_each_entry_safe(va, n_va, valist, purge_list) { 1281 llist_for_each_entry_safe(va, n_va, valist, purge_list) {
1283 unsigned long nr = (va->va_end - va->va_start) >> PAGE_SHIFT; 1282 unsigned long nr = (va->va_end - va->va_start) >> PAGE_SHIFT;
1284 1283
1285 __free_vmap_area(va); 1284 /*
1285 * Finally insert or merge lazily-freed area. It is
1286 * detached and there is no need to "unlink" it from
1287 * anything.
1288 */
1289 merge_or_add_vmap_area(va,
1290 &free_vmap_area_root, &free_vmap_area_list);
1291
1286 atomic_long_sub(nr, &vmap_lazy_nr); 1292 atomic_long_sub(nr, &vmap_lazy_nr);
1287 1293
1288 if (atomic_long_read(&vmap_lazy_nr) < resched_threshold) 1294 if (atomic_long_read(&vmap_lazy_nr) < resched_threshold)
@@ -1324,6 +1330,10 @@ static void free_vmap_area_noflush(struct vmap_area *va)
1324{ 1330{
1325 unsigned long nr_lazy; 1331 unsigned long nr_lazy;
1326 1332
1333 spin_lock(&vmap_area_lock);
1334 unlink_va(va, &vmap_area_root);
1335 spin_unlock(&vmap_area_lock);
1336
1327 nr_lazy = atomic_long_add_return((va->va_end - va->va_start) >> 1337 nr_lazy = atomic_long_add_return((va->va_end - va->va_start) >>
1328 PAGE_SHIFT, &vmap_lazy_nr); 1338 PAGE_SHIFT, &vmap_lazy_nr);
1329 1339
@@ -2143,14 +2153,13 @@ struct vm_struct *remove_vm_area(const void *addr)
2143 2153
2144 might_sleep(); 2154 might_sleep();
2145 2155
2146 va = find_vmap_area((unsigned long)addr); 2156 spin_lock(&vmap_area_lock);
2157 va = __find_vmap_area((unsigned long)addr);
2147 if (va && va->flags & VM_VM_AREA) { 2158 if (va && va->flags & VM_VM_AREA) {
2148 struct vm_struct *vm = va->vm; 2159 struct vm_struct *vm = va->vm;
2149 2160
2150 spin_lock(&vmap_area_lock);
2151 va->vm = NULL; 2161 va->vm = NULL;
2152 va->flags &= ~VM_VM_AREA; 2162 va->flags &= ~VM_VM_AREA;
2153 va->flags |= VM_LAZY_FREE;
2154 spin_unlock(&vmap_area_lock); 2163 spin_unlock(&vmap_area_lock);
2155 2164
2156 kasan_free_shadow(vm); 2165 kasan_free_shadow(vm);
@@ -2158,6 +2167,8 @@ struct vm_struct *remove_vm_area(const void *addr)
2158 2167
2159 return vm; 2168 return vm;
2160 } 2169 }
2170
2171 spin_unlock(&vmap_area_lock);
2161 return NULL; 2172 return NULL;
2162} 2173}
2163 2174
@@ -3450,6 +3461,22 @@ static void show_numa_info(struct seq_file *m, struct vm_struct *v)
3450 } 3461 }
3451} 3462}
3452 3463
3464static void show_purge_info(struct seq_file *m)
3465{
3466 struct llist_node *head;
3467 struct vmap_area *va;
3468
3469 head = READ_ONCE(vmap_purge_list.first);
3470 if (head == NULL)
3471 return;
3472
3473 llist_for_each_entry(va, head, purge_list) {
3474 seq_printf(m, "0x%pK-0x%pK %7ld unpurged vm_area\n",
3475 (void *)va->va_start, (void *)va->va_end,
3476 va->va_end - va->va_start);
3477 }
3478}
3479
3453static int s_show(struct seq_file *m, void *p) 3480static int s_show(struct seq_file *m, void *p)
3454{ 3481{
3455 struct vmap_area *va; 3482 struct vmap_area *va;
@@ -3462,10 +3489,9 @@ static int s_show(struct seq_file *m, void *p)
3462 * behalf of vmap area is being tear down or vm_map_ram allocation. 3489 * behalf of vmap area is being tear down or vm_map_ram allocation.
3463 */ 3490 */
3464 if (!(va->flags & VM_VM_AREA)) { 3491 if (!(va->flags & VM_VM_AREA)) {
3465 seq_printf(m, "0x%pK-0x%pK %7ld %s\n", 3492 seq_printf(m, "0x%pK-0x%pK %7ld vm_map_ram\n",
3466 (void *)va->va_start, (void *)va->va_end, 3493 (void *)va->va_start, (void *)va->va_end,
3467 va->va_end - va->va_start, 3494 va->va_end - va->va_start);
3468 va->flags & VM_LAZY_FREE ? "unpurged vm_area" : "vm_map_ram");
3469 3495
3470 return 0; 3496 return 0;
3471 } 3497 }
@@ -3504,6 +3530,16 @@ static int s_show(struct seq_file *m, void *p)
3504 3530
3505 show_numa_info(m, v); 3531 show_numa_info(m, v);
3506 seq_putc(m, '\n'); 3532 seq_putc(m, '\n');
3533
3534 /*
3535 * As a final step, dump "unpurged" areas. Note,
3536 * that entire "/proc/vmallocinfo" output will not
3537 * be address sorted, because the purge list is not
3538 * sorted.
3539 */
3540 if (list_is_last(&va->list, &vmap_area_list))
3541 show_purge_info(m);
3542
3507 return 0; 3543 return 0;
3508} 3544}
3509 3545