stability fixes for vmalloc allocator
Subsystems (2)
Uladzislau Rezki (Sony)
maintainercover stability fixes for vmalloc allocator
Hello.
The vmalloc test driver(https://lkml.org/lkml/2019/1/2/52) has been added to the linux-next. Therefore i would like to fix some stability issues i identified using it. I explained those issues in detail here:
https://lkml.org/lkml/2018/10/19/786
There are two patches, i think they are pretty ready to go with, unless there are any comments from you.
Thank you!
--
Vlad Rezki
Uladzislau Rezki (Sony) (2):
mm/vmalloc: fix kernel BUG at mm/vmalloc.c:512!
mm: add priority threshold to __purge_vmap_area_lazy()
mm/vmalloc.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-)
Signature · 1 line
2.11.0
Uladzislau Rezki (Sony)
maintainerPATCH 1/2 mm/vmalloc: fix kernel BUG at mm/vmalloc.c:512!
One of the vmalloc stress test case triggers the kernel BUG():
<snip>
[60.562151] ------------[ cut here ]------------ [60.562154] kernel BUG at mm/vmalloc.c:512! [60.562206] invalid opcode: 0000 [#1] PREEMPT SMP PTI [60.562247] CPU: 0 PID: 430 Comm: vmalloc_test/0 Not tainted 4.20.0+ #161 [60.562293] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.2-1 04/01/2014 [60.562351] RIP: 0010:alloc_vmap_area+0x36f/0x390
<snip>
it can happen due to big align request resulting in overflowing of calculated address, i.e. it becomes 0 after ALIGN()'s fixup.
Fix it by checking if calculated address is within vstart/vend range.
--- mm/vmalloc.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
mm/vmalloc.c +5 -1
@@ -498,7 +498,11 @@ static struct vmap_area *alloc_vmap_area(unsigned long size, } found: -if (addr + size > vend) +/* +* Check also calculated address against the vstart, +* because it can be 0 because of big align request. +*/ +if (addr + size > vend || addr < vstart) goto overflow; va->va_start = addr;
Signature · 1 line
2.11.0
Uladzislau Rezki (Sony)
maintainerPATCH 2/2 mm: add priority threshold to __purge_vmap_area_lazy()
In reply to Uladzislau Rezki (Sony)commit 763b218ddfaf ("mm: add preempt points into__purge_vmap_area_lazy()")
introduced some preempt points, one of those is making an allocation more prioritized over lazy free of vmap areas.
Prioritizing an allocation over freeing does not work well all the time, i.e. it should be rather a compromise.
1) Number of lazy pages directly influence on busy list length thus on operations like: allocation, lookup, unmap, remove, etc.
2) Under heavy stress of vmalloc subsystem i run into a situation when memory usage gets increased hitting out_of_memory -> panic state due to completely blocking of logic that frees vmap areas in the __purge_vmap_area_lazy() function.
Establish a threshold passing which the freeing is prioritized back over allocation creating a balance between each other.
--- mm/vmalloc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
mm/vmalloc.c +12 -6
@@ -661,23 +661,27 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)struct llist_node *valist;struct vmap_area *va;struct vmap_area *n_va; -bool do_free = false; +int resched_threshold;lockdep_assert_held (&vmap_purge_lock); valist =llist_del_all (&vmap_purge_list); +if (unlikely (valist ==NULL )) +return false; + +/* +* TODO: to calculate a flush range without looping. +* The list can be up to lazy_max_pages() elements. +*/ llist_for_each_entry (va, valist, purge_list) {if (va->va_start < start) start = va->va_start;if (va->va_end > end) end = va->va_end; - do_free = true; } -if (!do_free) -return false; -flush_tlb_kernel_range (start, end); + resched_threshold = (int )lazy_max_pages () <<1 ;spin_lock (&vmap_area_lock);llist_for_each_entry_safe (va, n_va, valist, purge_list) {
@@ -685,7 +689,9 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)__free_vmap_area (va);atomic_sub (nr, &vmap_lazy_nr); -cond_resched_lock (&vmap_area_lock); + +if (atomic_read (&vmap_lazy_nr) < resched_threshold) +cond_resched_lock (&vmap_area_lock); }spin_unlock (&vmap_area_lock);return true;
Signature · 1 line
2.11.0
Andrew Morton
maintainerRe: [PATCH v1 2/2] mm: add priority threshold to __purge_vmap_area_lazy()
Quoted 12 lines · On Thu, 24 Jan 2019 12:56:48 +0100 "Uladzislau Rezki (Sony)"…
commit
763b218ddfaf("mm: add preempt points into__purge_vmap_area_lazy()")introduced some preempt points, one of those is making an allocation more prioritized over lazy free of vmap areas.
Prioritizing an allocation over freeing does not work well all the time, i.e. it should be rather a compromise.
1) Number of lazy pages directly influence on busy list length thus on operations like: allocation, lookup, unmap, remove, etc.
Quoted 7 lines
2) Under heavy stress of vmalloc subsystem i run into a situation when memory usage gets increased hitting
out_of_memory-> panic state due to completely blocking of logic that frees vmap areas in the__purge_vmap_area_lazy()function.Establish a threshold passing which the freeing is prioritized back over allocation creating a balance between each other.
It would be useful to credit the vmalloc test driver for this discovery, and perhaps to identify specifically which test triggered the kernel misbehaviour. Please send along suitable words and I'll add them.
Quoted 4 lines
mm/vmalloc.c +0
-0@@ -661,23 +661,27 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)struct llist_node *valist;
mm/vmalloc.c static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end) · line 670
Quoted 10 lines
mm/vmalloc.c +3
-1struct vmap_area *va;struct vmap_area *n_va; -bool do_free = false; +int resched_threshold;lockdep_assert_held (&vmap_purge_lock); valist =llist_del_all (&vmap_purge_list); +if (unlikely (valist ==NULL )) +return false;
Why this change?
mm/vmalloc.c static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end) · line 675
Quoted 4 lines
mm/vmalloc.c +4
-0+/* +* TODO: to calculate a flush range without looping. +* The list can be up to lazy_max_pages() elements. +*/
How important is this?
mm/vmalloc.c static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end) · line 684
Quoted 13 lines
mm/vmalloc.c +1
-4llist_for_each_entry (va, valist, purge_list) {if (va->va_start < start) start = va->va_start;if (va->va_end > end) end = va->va_end; - do_free = true; } -if (!do_free) -return false; -flush_tlb_kernel_range (start, end); + resched_threshold = (int )lazy_max_pages () <<1 ;
Is the typecast really needed?
Perhaps resched_threshold shiould have unsigned long type and perhaps vmap_lazy_nr should be atomic_long_t?
Quoted 13 lines
mm/vmalloc.c +3
-1spin_lock (&vmap_area_lock);llist_for_each_entry_safe (va, n_va, valist, purge_list) {@@ -685,7 +689,9 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)__free_vmap_area (va);atomic_sub (nr, &vmap_lazy_nr); -cond_resched_lock (&vmap_area_lock); + +if (atomic_read (&vmap_lazy_nr) < resched_threshold) +cond_resched_lock (&vmap_area_lock); }spin_unlock (&vmap_area_lock);return true;
Uladzislau Rezki
maintainerRe: [PATCH v1 2/2] mm: add priority threshold to __purge_vmap_area_lazy()
Quoted 19 lines · Andrew Morton
Quoted 17 lines · On Thu, 24 Jan 2019 12:56:48 +0100 "Uladzislau Rezki (Sony)"…
commit
763b218ddfaf("mm: add preempt points into__purge_vmap_area_lazy()")introduced some preempt points, one of those is making an allocation more prioritized over lazy free of vmap areas.
Prioritizing an allocation over freeing does not work well all the time, i.e. it should be rather a compromise.
1) Number of lazy pages directly influence on busy list length thus on operations like: allocation, lookup, unmap, remove, etc.
2) Under heavy stress of vmalloc subsystem i run into a situation when memory usage gets increased hitting
out_of_memory-> panic state due to completely blocking of logic that frees vmap areas in the__purge_vmap_area_lazy()function.
Quoted 8 lines
Quoted 2 lines
Establish a threshold passing which the freeing is prioritized back over allocation creating a balance between each other.
It would be useful to credit the vmalloc test driver for this discovery, and perhaps to identify specifically which test triggered the kernel misbehaviour. Please send along suitable words and I'll add them.
Please see below more detail of testing:
<snip>
Using vmalloc test driver in "stress mode", i.e. When all available test cases are run simultaneously on all online CPUs applying a pressure on the vmalloc subsystem, my HiKey 960 board runs out of memory due to the fact that __purge_vmap_area_lazy() logic simply is not able to free pages in time.
How i run it:
1) You should build your kernel with CONFIG_TEST_VMALLOC=m
2) ./tools/testing/selftests/vm/test_vmalloc.sh stress
during this test "vmap_lazy_nr" pages will go far beyond acceptable lazy_max_pages() threshold, that will lead to enormous busy list size and other problems including allocation time and so on. <snip>
Quoted 10 lines
Quoted 10 lines
mm/vmalloc.c +1
-1@@ -661,23 +661,27 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)struct llist_node *valist;struct vmap_area *va;struct vmap_area *n_va; -bool do_free = false; +int resched_threshold;
Quoted 8 lines
mm/vmalloc.c static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end) · line 670
Quoted 5 lines
mm/vmalloc.c +2
-0lockdep_assert_held (&vmap_purge_lock); valist =llist_del_all (&vmap_purge_list); +if (unlikely (valist ==NULL )) +return false;Why this change?
I decided to refactor a bit, simplify and get rid of unneeded do_free check logic. I think it is more straightforward just to check if list is empty or not, instead of accessing to "do_free" "n" times in a loop.
I can drop it, or upload as separate patch. What is your view?
Quoted 7 lines
mm/vmalloc.c static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end) · line 675
Quoted 4 lines
mm/vmalloc.c +4
-0+/* +* TODO: to calculate a flush range without looping. +* The list can be up to lazy_max_pages() elements. +*/ How important is this?
It depends on vmap_lazy_nr pages in the list we iterate. For example on my ARM 8 cores with 4Gb system i see that __purge_vmap_area_lazy() can take up to 12 milliseconds because of long list. That is why there is the cond_resched_lock().
As for this first loop's time execution, it takes ~4/5 milliseconds to find out the flush range. Probably it is not so important since it is not done in atomic context means it can be interrupted or preempted. So, it will increase execution time of the current process that does:
vfree()/etc -> __purge_vmap_area_lazy().
From the other hand if we could calculate that range in runtime, i mean when we add a VA to the vmap_purge_list checking va->va_start and va->va_end with min/max we could get rid of that loop. But this is just an idea.
Quoted 16 lines
mm/vmalloc.c static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end) · line 684
Quoted 13 lines
mm/vmalloc.c +1
-4llist_for_each_entry (va, valist, purge_list) {if (va->va_start < start) start = va->va_start;if (va->va_end > end) end = va->va_end; - do_free = true; } -if (!do_free) -return false; -flush_tlb_kernel_range (start, end); + resched_threshold = (int )lazy_max_pages () <<1 ;Is the typecast really needed?
Quoted 3 lines
Perhaps
resched_thresholdshiould have unsigned long type and perhapsvmap_lazy_nrshould beatomic_long_t?
I think so. Especially that atomit_t is 32 bit integer value on both 32 and 64 bit systems. lazy_max_pages() deals with unsigned long that is 8 bytes on 64 bit system, thus vmap_lazy_nr should be 8 bytes on 64 bit as well.
Should i send it as separate patch? What is your view?
Quoted 4 lines
Quoted 4 lines
mm/vmalloc.c +0
-0spin_lock (&vmap_area_lock);llist_for_each_entry_safe (va, n_va, valist, purge_list) {@@ -685,7 +689,9 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)
Quoted 10 lines
mm/vmalloc.c static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end) · line 697
Quoted 9 lines
mm/vmalloc.c +3
-1__free_vmap_area (va);atomic_sub (nr, &vmap_lazy_nr); -cond_resched_lock (&vmap_area_lock); + +if (atomic_read (&vmap_lazy_nr) < resched_threshold) +cond_resched_lock (&vmap_area_lock); }spin_unlock (&vmap_area_lock);return true;
Thank you for your comments and review.
--
Vlad Rezki
Andrew Morton
maintainerRe: [PATCH v1 2/2] mm: add priority threshold to __purge_vmap_area_lazy()
Quoted 7 lines · On Tue, 29 Jan 2019 17:17:54 +0100 Uladzislau Rezki <[email protected]> wrote:
Quoted 7 lines
mm/vmalloc.c static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end) · line 684
Quoted 1 line
mm/vmalloc.c +1
-0+ resched_threshold = (int )lazy_max_pages () <<1 ;Is the typecast really needed?
Perhaps
resched_thresholdshiould have unsigned long type and perhapsvmap_lazy_nrshould beatomic_long_t?
Quoted 6 lines
I think so. Especially that
atomit_tis 32 bit integer value on both 32 and 64 bit systems.lazy_max_pages()deals with unsigned long that is 8 bytes on 64 bit system, thusvmap_lazy_nrshould be 8 bytes on 64 bit as well.Should i send it as separate patch? What is your view?
Sounds good. When convenient, please.
Re: [PATCH v1 2/2] mm: add priority threshold to __purge_vmap_area_lazy()
In reply to Uladzislau Rezki (Sony)Quoted 12 lines · Uladzislau Rezki (Sony)
commit
763b218ddfaf("mm: add preempt points into__purge_vmap_area_lazy()")introduced some preempt points, one of those is making an allocation more prioritized over lazy free of vmap areas.
Prioritizing an allocation over freeing does not work well all the time, i.e. it should be rather a compromise.
1) Number of lazy pages directly influence on busy list length thus on operations like: allocation, lookup, unmap, remove, etc.
Quoted 7 lines
2) Under heavy stress of vmalloc subsystem i run into a situation when memory usage gets increased hitting
out_of_memory-> panic state due to completely blocking of logic that frees vmap areas in the__purge_vmap_area_lazy()function.Establish a threshold passing which the freeing is prioritized back over allocation creating a balance between each other.
I'm a bit concerned that this will introduce the latency back if vmap_lazy_nr is greater than half of lazy_max_pages(). Which IIUC will be more likely if the number of CPUs is large.
In fact, when vmap_lazy_nr is high, that's when the latency will be the worst so one could say that that's when you *should* reschedule since the frees are taking too long and hurting real-time tasks.
Could this be better solved by tweaking lazy_max_pages() such that purging is more aggressive?
Another approach could be to detect the scenario you brought up (allocations happening faster than free), somehow, and avoid a reschedule?
thanks,
- Joel
Quoted 57 lines
Signed-off-by Uladzislau Rezki (Sony) <[email protected]>--- mm/vmalloc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)mm/vmalloc.c +12
-6@@ -661,23 +661,27 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)struct llist_node *valist;struct vmap_area *va;struct vmap_area *n_va; -bool do_free = false; +int resched_threshold;lockdep_assert_held (&vmap_purge_lock); valist =llist_del_all (&vmap_purge_list); +if (unlikely (valist ==NULL )) +return false; + +/* +* TODO: to calculate a flush range without looping. +* The list can be up to lazy_max_pages() elements. +*/ llist_for_each_entry (va, valist, purge_list) {if (va->va_start < start) start = va->va_start;if (va->va_end > end) end = va->va_end; - do_free = true; } -if (!do_free) -return false; -flush_tlb_kernel_range (start, end); + resched_threshold = (int )lazy_max_pages () <<1 ;spin_lock (&vmap_area_lock);llist_for_each_entry_safe (va, n_va, valist, purge_list) {@@ -685,7 +689,9 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)__free_vmap_area (va);atomic_sub (nr, &vmap_lazy_nr); -cond_resched_lock (&vmap_area_lock); + +if (atomic_read (&vmap_lazy_nr) < resched_threshold) +cond_resched_lock (&vmap_area_lock); }spin_unlock (&vmap_area_lock);return true;Signature · 1 line
2.11.0
Uladzislau Rezki
maintainerRe: [PATCH v1 2/2] mm: add priority threshold to __purge_vmap_area_lazy()
Quoted 18 lines · Joel Fernandes
Quoted 17 lines · Uladzislau Rezki (Sony)
commit
763b218ddfaf("mm: add preempt points into__purge_vmap_area_lazy()")introduced some preempt points, one of those is making an allocation more prioritized over lazy free of vmap areas.
Prioritizing an allocation over freeing does not work well all the time, i.e. it should be rather a compromise.
1) Number of lazy pages directly influence on busy list length thus on operations like: allocation, lookup, unmap, remove, etc.
2) Under heavy stress of vmalloc subsystem i run into a situation when memory usage gets increased hitting
out_of_memory-> panic state due to completely blocking of logic that frees vmap areas in the__purge_vmap_area_lazy()function.
Quoted 7 lines
Quoted 2 lines
Establish a threshold passing which the freeing is prioritized back over allocation creating a balance between each other.
I'm a bit concerned that this will introduce the latency back if
vmap_lazy_nris greater than half oflazy_max_pages(). Which IIUC will be more likely if the number of CPUs is large.
The threshold that we establish is two times more than lazy_max_pages(), i.e. in case of 4 system CPUs lazy_max_pages() is 24576, therefore the threshold is 49152, if PAGE_SIZE is 4096.
It means that we allow rescheduling if vmap_lazy_nr < 49152. If vmap_lazy_nr is higher then we forbid rescheduling and free areas until it becomes lower again to stabilize the system. By doing that, we will not allow vmap_lazy_nr to be enormously increased.
Quoted 11 lines
In fact, when
vmap_lazy_nris high, that's when the latency will be the worst so one could say that that's when you *should* reschedule since the frees are taking too long and hurting real-time tasks.Could this be better solved by tweaking
lazy_max_pages()such that purging is more aggressive?Another approach could be to detect the scenario you brought up (allocations happening faster than free), somehow, and avoid a reschedule?
This is what i am trying to achieve by this change.
Thank you for your comments.
--
Vlad Rezki
Quoted 57 lines
Quoted 57 lines
Signed-off-by Uladzislau Rezki (Sony) <[email protected]>--- mm/vmalloc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)mm/vmalloc.c +12
-6@@ -661,23 +661,27 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)struct llist_node *valist;struct vmap_area *va;struct vmap_area *n_va; -bool do_free = false; +int resched_threshold;lockdep_assert_held (&vmap_purge_lock); valist =llist_del_all (&vmap_purge_list); +if (unlikely (valist ==NULL )) +return false; + +/* +* TODO: to calculate a flush range without looping. +* The list can be up to lazy_max_pages() elements. +*/ llist_for_each_entry (va, valist, purge_list) {if (va->va_start < start) start = va->va_start;if (va->va_end > end) end = va->va_end; - do_free = true; } -if (!do_free) -return false; -flush_tlb_kernel_range (start, end); + resched_threshold = (int )lazy_max_pages () <<1 ;spin_lock (&vmap_area_lock);llist_for_each_entry_safe (va, n_va, valist, purge_list) {@@ -685,7 +689,9 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)__free_vmap_area (va);atomic_sub (nr, &vmap_lazy_nr); -cond_resched_lock (&vmap_area_lock); + +if (atomic_read (&vmap_lazy_nr) < resched_threshold) +cond_resched_lock (&vmap_area_lock); }spin_unlock (&vmap_area_lock);return true;Signature · 1 line
2.11.0
Re: [PATCH v1 2/2] mm: add priority threshold to __purge_vmap_area_lazy()
Quoted 26 lines · Uladzislau Rezki
Quoted 18 lines · Joel Fernandes
Quoted 17 lines · Uladzislau Rezki (Sony)
commit
763b218ddfaf("mm: add preempt points into__purge_vmap_area_lazy()")introduced some preempt points, one of those is making an allocation more prioritized over lazy free of vmap areas.
Prioritizing an allocation over freeing does not work well all the time, i.e. it should be rather a compromise.
1) Number of lazy pages directly influence on busy list length thus on operations like: allocation, lookup, unmap, remove, etc.
2) Under heavy stress of vmalloc subsystem i run into a situation when memory usage gets increased hitting
out_of_memory-> panic state due to completely blocking of logic that frees vmap areas in the__purge_vmap_area_lazy()function.Quoted 7 lines
Quoted 2 lines
Establish a threshold passing which the freeing is prioritized back over allocation creating a balance between each other.
I'm a bit concerned that this will introduce the latency back if
vmap_lazy_nris greater than half oflazy_max_pages(). Which IIUC will be more likely if the number of CPUs is large.
Quoted 8 lines
The threshold that we establish is two times more than
lazy_max_pages(), i.e. in case of 4 system CPUslazy_max_pages()is 24576, therefore the threshold is 49152, ifPAGE_SIZEis 4096.It means that we allow rescheduling if
vmap_lazy_nr< 49152. Ifvmap_lazy_nris higher then we forbid rescheduling and free areas until it becomes lower again to stabilize the system. By doing that, we will not allowvmap_lazy_nrto be enormously increased.
Sorry for late reply.
This sounds reasonable. Such an extreme situation of vmap_lazy_nr being twice the lazy_max_pages() is probably only possible using a stress test anyway since (hopefully) the try_purge_vmap_area_lazy() call is happening often enough to keep the vmap_lazy_nr low.
Have you experimented with what is the highest threshold that prevents the issues you're seeing? Have you tried 3x or 4x the vmap_lazy_nr?
I also wonder what is the cost these days of the global TLB flush on the most common Linux architectures and if the whole purge vmap_area lazy stuff is starting to get a bit dated, and if we can do the purging inline as areas are freed. There is a cost to having this mechanism too as you said, which is as the list size grows, all other operations also take time.
thanks,
- Joel
Quoted 73 lines
Quoted 10 lines
In fact, when
vmap_lazy_nris high, that's when the latency will be the worst so one could say that that's when you *should* reschedule since the frees are taking too long and hurting real-time tasks.Could this be better solved by tweaking
lazy_max_pages()such that purging is more aggressive?Another approach could be to detect the scenario you brought up (allocations happening faster than free), somehow, and avoid a reschedule?
This is what i am trying to achieve by this change.
Thank you for your comments.
--
Vlad RezkiQuoted 57 lines
Quoted 57 lines
Signed-off-by Uladzislau Rezki (Sony) <[email protected]>--- mm/vmalloc.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)mm/vmalloc.c +12
-6@@ -661,23 +661,27 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)struct llist_node *valist;struct vmap_area *va;struct vmap_area *n_va; -bool do_free = false; +int resched_threshold;lockdep_assert_held (&vmap_purge_lock); valist =llist_del_all (&vmap_purge_list); +if (unlikely (valist ==NULL )) +return false; + +/* +* TODO: to calculate a flush range without looping. +* The list can be up to lazy_max_pages() elements. +*/ llist_for_each_entry (va, valist, purge_list) {if (va->va_start < start) start = va->va_start;if (va->va_end > end) end = va->va_end; - do_free = true; } -if (!do_free) -return false; -flush_tlb_kernel_range (start, end); + resched_threshold = (int )lazy_max_pages () <<1 ;spin_lock (&vmap_area_lock);llist_for_each_entry_safe (va, n_va, valist, purge_list) {@@ -685,7 +689,9 @@ static bool __purge_vmap_area_lazy(unsigned long start, unsigned long end)__free_vmap_area (va);atomic_sub (nr, &vmap_lazy_nr); -cond_resched_lock (&vmap_area_lock); + +if (atomic_read (&vmap_lazy_nr) < resched_threshold) +cond_resched_lock (&vmap_area_lock); }spin_unlock (&vmap_area_lock);return true;Signature · 1 line
2.11.0
Uladzislau Rezki
maintainerRe: [PATCH v1 2/2] mm: add priority threshold to __purge_vmap_area_lazy()
Quoted 16 lines
Quoted 5 lines
Quoted 5 lines
I'm a bit concerned that this will introduce the latency back if
vmap_lazy_nris greater than half oflazy_max_pages(). Which IIUC will be more likely if the number of CPUs is large.Quoted 8 lines
The threshold that we establish is two times more than
lazy_max_pages(), i.e. in case of 4 system CPUslazy_max_pages()is 24576, therefore the threshold is 49152, ifPAGE_SIZEis 4096.It means that we allow rescheduling if
vmap_lazy_nr< 49152. Ifvmap_lazy_nris higher then we forbid rescheduling and free areas until it becomes lower again to stabilize the system. By doing that, we will not allowvmap_lazy_nrto be enormously increased.Sorry for late reply.
Quoted 8 lines
This sounds reasonable. Such an extreme situation of
vmap_lazy_nrbeing twice thelazy_max_pages()is probably only possible using a stress test anyway since (hopefully) thetry_purge_vmap_area_lazy()call is happening often enough to keep thevmap_lazy_nrlow.Have you experimented with what is the highest threshold that prevents the issues you're seeing? Have you tried 3x or 4x the
vmap_lazy_nr?
I do not think it make sense to go with 3x/4x/etc threshold for many reasons. One of them is we just need to prevent that skew, returning back to reasonable balance.
Quoted 7 lines
I also wonder what is the cost these days of the global TLB flush on the most common Linux architectures and if the whole purge
vmap_arealazy stuff is starting to get a bit dated, and if we can do the purging inline as areas are freed. There is a cost to having this mechanism too as you said, which is as the list size grows, all other operations also take time.
I guess if we go with flushing the TLB each time per each vmap_area freeing, then i think we are in trouble. Though, i have not analyzed how that approach impacts performance.
I agree about the cost of having such mechanism. Basically it is one of the source of bigger fragmentation(not limited to it). But from the other hand the KVA allocator has to be capable of effective and fast allocation even in that condition.
I am working on v2 of https://lkml.org/lkml/2018/10/19/786. When i complete some other job related tasks i will upload a new RFC.
--
Vlad Rezki