* Re: [patch 1/3] mm: An enhancement of OVERCOMMIT_GUESS
From: KAMEZAWA Hiroyuki @ 2006-04-06 8:08 UTC (permalink / raw)
To: Hideo AOKI; +Cc: akpm, linux-kernel, linux-mm
In-Reply-To: <4434C12A.4000108@redhat.com>
On Thu, 06 Apr 2006 03:20:10 -0400
Hideo AOKI <haoki@redhat.com> wrote:
> Hi Kamezawa-san,
>
> Thank you for your comments.
>
> KAMEZAWA Hiroyuki wrote:
> > Hi, AOKI-san
> I like your idea. But, in the function, I think we need to care
> lowmem_reserve too.
>
Ah, I see.
> Since __vm_enough_memory() doesn't know zone and cpuset information,
> we have to guess proper value of lowmem_reserve in each zone
> like I did in calculate_totalreserve_pages() in my patch.
> Do you think that we can do this calculation every time?
>
> If it is good enough, I'll make revised patch.
>
I just thought to show "how to calculate" in unified way is better.
But if things goes ugly, please ignore my comment.
Do you have a detailed comparison of test result with and without this patch ?
I'm interested in.
I'm sorry if I missed your post of result.
Cheers!
-Kame
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [patch 1/3] mm: An enhancement of OVERCOMMIT_GUESS
From: Hideo AOKI @ 2006-04-06 7:20 UTC (permalink / raw)
To: KAMEZAWA Hiroyuki; +Cc: akpm, linux-kernel, linux-mm
In-Reply-To: <20060406094533.b340f633.kamezawa.hiroyu@jp.fujitsu.com>
Hi Kamezawa-san,
Thank you for your comments.
KAMEZAWA Hiroyuki wrote:
> Hi, AOKI-san
>
> On Wed, 05 Apr 2006 19:47:27 -0400
> Hideo AOKI <haoki@redhat.com> wrote:
>
>
>>Hello Andrew,
>>
>>Could you apply my patches to your tree?
>>
>>These patches are an enhancement of OVERCOMMIT_GUESS algorithm in
>>__vm_enough_memory(). The detailed description is in attached patch.
>
> I think adding a function like this is more simple way.
> (call this istead of nr_free_pages().)
> ==
> int nr_available_memory()
> {
> unsigned long sum = 0;
> for_each_zone(zone) {
> if (zone->free_pages > zone->pages_high)
> sum += zone->free_pages - zone->pages_high;
> }
> return sum;
> }
> ==
I like your idea. But, in the function, I think we need to care
lowmem_reserve too.
Since __vm_enough_memory() doesn't know zone and cpuset information,
we have to guess proper value of lowmem_reserve in each zone
like I did in calculate_totalreserve_pages() in my patch.
Do you think that we can do this calculation every time?
If it is good enough, I'll make revised patch.
> BTW, vm_enough_memory() doesn't eat cpuset information ?
I think this is another point which we should improve.
Best regards,
Hideo Aoki
---
Hideo Aoki, Hitachi Computer Products (America) Inc.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: Respin: [PATCH] mm: limit lowmem_reserve
From: Con Kolivas @ 2006-04-06 4:52 UTC (permalink / raw)
To: ck; +Cc: Andrew Morton, nickpiggin, linux-kernel, linux-mm
In-Reply-To: <200604061436.16907.kernel@kolivas.org>
On Thursday 06 April 2006 14:36, Con Kolivas wrote:
> On Thursday 06 April 2006 13:40, Andrew Morton wrote:
> > Con Kolivas <kernel@kolivas.org> wrote:
> > > On Thursday 06 April 2006 12:55, Con Kolivas wrote:
> > > > On Thursday 06 April 2006 12:43, Andrew Morton wrote:
> > > > > Con Kolivas <kernel@kolivas.org> wrote:
> > > > > > It is possible with a low enough lowmem_reserve ratio to make
> > > > > > zone_watermark_ok fail repeatedly if the lower_zone is small
> > > > > > enough.
> > > > >
> > > > > Is that actually a problem?
> > > >
> > > > Every single call to get_page_from_freelist will call on zone
> > > > reclaim. It seems a problem to me if every call to __alloc_pages will
> > > > do that?
> > >
> > > every call to __alloc_pages of that zone I mean
> >
> > One would need to check with the NUMA guys. zone_reclaim() has a
> > (lame-looking) timer in there to prevent it from doing too much work.
> >
> > That, or I'm missing something. This problem wasn't particularly well
> > described, sorry.
>
> Ah ok. This all came about because I'm trying to honour the lowmem_reserve
> better in swap_prefetch at Nick's request. It's hard to honour a watermark
> that on some configurations is never reached.
Forget that. If the numa people don't care about it I shouldn't touch it. I
thought I was doing something helpful at the source but got no response from
Nick or the the other numa_ids out there so they obviously don't care. I'll
tackle it differently in swap prefetch.
Cheers,
Con
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: Respin: [PATCH] mm: limit lowmem_reserve
From: Con Kolivas @ 2006-04-06 4:36 UTC (permalink / raw)
To: Andrew Morton; +Cc: ck, nickpiggin, linux-kernel, linux-mm
In-Reply-To: <20060405204009.3235b021.akpm@osdl.org>
On Thursday 06 April 2006 13:40, Andrew Morton wrote:
> Con Kolivas <kernel@kolivas.org> wrote:
> > On Thursday 06 April 2006 12:55, Con Kolivas wrote:
> > > On Thursday 06 April 2006 12:43, Andrew Morton wrote:
> > > > Con Kolivas <kernel@kolivas.org> wrote:
> > > > > It is possible with a low enough lowmem_reserve ratio to make
> > > > > zone_watermark_ok fail repeatedly if the lower_zone is small
> > > > > enough.
> > > >
> > > > Is that actually a problem?
> > >
> > > Every single call to get_page_from_freelist will call on zone reclaim.
> > > It seems a problem to me if every call to __alloc_pages will do that?
> >
> > every call to __alloc_pages of that zone I mean
>
> One would need to check with the NUMA guys. zone_reclaim() has a
> (lame-looking) timer in there to prevent it from doing too much work.
>
> That, or I'm missing something. This problem wasn't particularly well
> described, sorry.
Ah ok. This all came about because I'm trying to honour the lowmem_reserve
better in swap_prefetch at Nick's request. It's hard to honour a watermark
that on some configurations is never reached.
Cheers,
Con
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: Respin: [PATCH] mm: limit lowmem_reserve
From: Andrew Morton @ 2006-04-06 3:40 UTC (permalink / raw)
To: Con Kolivas; +Cc: ck, nickpiggin, linux-kernel, linux-mm
In-Reply-To: <200604061258.40487.kernel@kolivas.org>
Con Kolivas <kernel@kolivas.org> wrote:
>
> On Thursday 06 April 2006 12:55, Con Kolivas wrote:
> > On Thursday 06 April 2006 12:43, Andrew Morton wrote:
> > > Con Kolivas <kernel@kolivas.org> wrote:
> > > > It is possible with a low enough lowmem_reserve ratio to make
> > > > zone_watermark_ok fail repeatedly if the lower_zone is small enough.
> > >
> > > Is that actually a problem?
> >
> > Every single call to get_page_from_freelist will call on zone reclaim. It
> > seems a problem to me if every call to __alloc_pages will do that?
>
> every call to __alloc_pages of that zone I mean
>
One would need to check with the NUMA guys. zone_reclaim() has a
(lame-looking) timer in there to prevent it from doing too much work.
That, or I'm missing something. This problem wasn't particularly well
described, sorry.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: Respin: [PATCH] mm: limit lowmem_reserve
From: Con Kolivas @ 2006-04-06 2:58 UTC (permalink / raw)
To: ck; +Cc: Andrew Morton, nickpiggin, linux-kernel, linux-mm
In-Reply-To: <200604061255.55055.kernel@kolivas.org>
On Thursday 06 April 2006 12:55, Con Kolivas wrote:
> On Thursday 06 April 2006 12:43, Andrew Morton wrote:
> > Con Kolivas <kernel@kolivas.org> wrote:
> > > It is possible with a low enough lowmem_reserve ratio to make
> > > zone_watermark_ok fail repeatedly if the lower_zone is small enough.
> >
> > Is that actually a problem?
>
> Every single call to get_page_from_freelist will call on zone reclaim. It
> seems a problem to me if every call to __alloc_pages will do that?
every call to __alloc_pages of that zone I mean
Cheers,
Con
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: Respin: [PATCH] mm: limit lowmem_reserve
From: Con Kolivas @ 2006-04-06 2:55 UTC (permalink / raw)
To: Andrew Morton; +Cc: linux-kernel, ck, nickpiggin, linux-mm
In-Reply-To: <20060405194344.1915b57a.akpm@osdl.org>
On Thursday 06 April 2006 12:43, Andrew Morton wrote:
> Con Kolivas <kernel@kolivas.org> wrote:
> > It is possible with a low enough lowmem_reserve ratio to make
> > zone_watermark_ok fail repeatedly if the lower_zone is small enough.
>
> Is that actually a problem?
Every single call to get_page_from_freelist will call on zone reclaim. It
seems a problem to me if every call to __alloc_pages will do that?
Cheers,
Con
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: Respin: [PATCH] mm: limit lowmem_reserve
From: Andrew Morton @ 2006-04-06 2:43 UTC (permalink / raw)
To: Con Kolivas; +Cc: linux-kernel, ck, nickpiggin, linux-mm
In-Reply-To: <200604061129.41658.kernel@kolivas.org>
Con Kolivas <kernel@kolivas.org> wrote:
>
> It is possible with a low enough lowmem_reserve ratio to make
> zone_watermark_ok fail repeatedly if the lower_zone is small enough.
Is that actually a problem?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Respin: [PATCH] mm: limit lowmem_reserve
From: Con Kolivas @ 2006-04-06 1:29 UTC (permalink / raw)
To: linux-kernel; +Cc: Andrew Morton, ck, Nick Piggin, linux-mm
In-Reply-To: <200604061110.35789.kernel@kolivas.org>
Err zone needs to have some pages too sorry.
Respin
---
It is possible with a low enough lowmem_reserve ratio to make
zone_watermark_ok fail repeatedly if the lower_zone is small enough.
Impose a lower limit on the ratio to only allow 1/4 of the lower_zone
size to be set as lowmem_reserve. This limit is hit in ZONE_DMA by changing
the default vmsplit on i386 even without changing the default sysctl values.
Signed-off-by: Con Kolivas <kernel@kolivas.org>
---
mm/page_alloc.c | 24 +++++++++++++++++++++---
1 files changed, 21 insertions(+), 3 deletions(-)
Index: linux-2.6.17-rc1-mm1/mm/page_alloc.c
===================================================================
--- linux-2.6.17-rc1-mm1.orig/mm/page_alloc.c 2006-04-06 10:32:31.000000000 +1000
+++ linux-2.6.17-rc1-mm1/mm/page_alloc.c 2006-04-06 11:28:11.000000000 +1000
@@ -2566,14 +2566,32 @@ static void setup_per_zone_lowmem_reserv
zone->lowmem_reserve[j] = 0;
for (idx = j-1; idx >= 0; idx--) {
+ unsigned long max_reserve;
+ unsigned long reserve;
struct zone *lower_zone;
+ lower_zone = pgdat->node_zones + idx;
+ /*
+ * Put an upper limit on the reserve at 1/4
+ * the lower_zone size. This prevents large
+ * zone size differences such as 3G VMSPLIT
+ * or low sysctl values from making
+ * zone_watermark_ok always fail. This
+ * enforces a lower limit on the reserve_ratio
+ */
+ max_reserve = lower_zone->present_pages / 4;
+
if (sysctl_lowmem_reserve_ratio[idx] < 1)
sysctl_lowmem_reserve_ratio[idx] = 1;
-
- lower_zone = pgdat->node_zones + idx;
- lower_zone->lowmem_reserve[j] = present_pages /
+ reserve = present_pages /
sysctl_lowmem_reserve_ratio[idx];
+ if (max_reserve && reserve > max_reserve) {
+ reserve = max_reserve;
+ sysctl_lowmem_reserve_ratio[idx] =
+ present_pages / max_reserve;
+ }
+
+ lower_zone->lowmem_reserve[j] = reserve;
present_pages += lower_zone->present_pages;
}
}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* [PATCH] mm: limit lowmem_reserve
From: Con Kolivas @ 2006-04-06 1:10 UTC (permalink / raw)
To: Andrew Morton; +Cc: ck, Nick Piggin, linux list, linux-mm
In-Reply-To: <200604041235.59876.kernel@kolivas.org>
It is possible with a low enough lowmem_reserve ratio to make
zone_watermark_ok always fail if the lower_zone is small enough.
Impose a lower limit on the ratio to only allow 1/4 of the lower_zone
size to be set as lowmem_reserve. This limit is hit in ZONE_DMA by changing
the default vmsplit on i386 even without changing the default sysctl values.
Signed-off-by: Con Kolivas <kernel@kolivas.org>
---
mm/page_alloc.c | 24 +++++++++++++++++++++---
1 files changed, 21 insertions(+), 3 deletions(-)
Index: linux-2.6.17-rc1-mm1/mm/page_alloc.c
===================================================================
--- linux-2.6.17-rc1-mm1.orig/mm/page_alloc.c 2006-04-06 10:32:31.000000000 +1000
+++ linux-2.6.17-rc1-mm1/mm/page_alloc.c 2006-04-06 11:09:17.000000000 +1000
@@ -2566,14 +2566,32 @@ static void setup_per_zone_lowmem_reserv
zone->lowmem_reserve[j] = 0;
for (idx = j-1; idx >= 0; idx--) {
+ unsigned long max_reserve;
+ unsigned long reserve;
struct zone *lower_zone;
+ lower_zone = pgdat->node_zones + idx;
+ /*
+ * Put an upper limit on the reserve at 1/4
+ * the lower_zone size. This prevents large
+ * zone size differences such as 3G VMSPLIT
+ * or low sysctl values from making
+ * zone_watermark_ok always fail. This
+ * enforces a lower limit on the reserve_ratio
+ */
+ max_reserve = lower_zone->present_pages / 4;
+
if (sysctl_lowmem_reserve_ratio[idx] < 1)
sysctl_lowmem_reserve_ratio[idx] = 1;
-
- lower_zone = pgdat->node_zones + idx;
- lower_zone->lowmem_reserve[j] = present_pages /
+ reserve = present_pages /
sysctl_lowmem_reserve_ratio[idx];
+ if (reserve > max_reserve) {
+ reserve = max_reserve;
+ sysctl_lowmem_reserve_ratio[idx] =
+ present_pages / max_reserve;
+ }
+
+ lower_zone->lowmem_reserve[j] = reserve;
present_pages += lower_zone->present_pages;
}
}
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [patch 1/3] mm: An enhancement of OVERCOMMIT_GUESS
From: KAMEZAWA Hiroyuki @ 2006-04-06 0:45 UTC (permalink / raw)
To: Hideo AOKI; +Cc: akpm, linux-kernel, linux-mm
In-Reply-To: <4434570F.9030507@redhat.com>
Hi, AOKI-san
On Wed, 05 Apr 2006 19:47:27 -0400
Hideo AOKI <haoki@redhat.com> wrote:
> Hello Andrew,
>
> Could you apply my patches to your tree?
>
> These patches are an enhancement of OVERCOMMIT_GUESS algorithm in
> __vm_enough_memory(). The detailed description is in attached patch.
>
I think adding a function like this is more simple way.
(call this istead of nr_free_pages().)
==
int nr_available_memory()
{
unsigned long sum = 0;
for_each_zone(zone) {
if (zone->free_pages > zone->pages_high)
sum += zone->free_pages - zone->pages_high;
}
return sum;
}
==
BTW, vm_enough_memory() doesn't eat cpuset information ?
-Kame
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* A patch for test_overcommit module
From: Hideo AOKI @ 2006-04-05 23:52 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, linux-mm
In-Reply-To: <4434570F.9030507@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 161 bytes --]
The test module needs this kernel patch.
I don't intend to propose to apply this patch to kernel tree.
---
Hideo Aoki, Hitachi Computer Products (America) Inc.
[-- Attachment #2: mm-debug.patch --]
[-- Type: text/x-patch, Size: 2086 bytes --]
This patch exports the symbols which a kernel module has to refer.
include/linux/mman.h | 1 +
mm/page_alloc.c | 1 +
mm/slab.c | 1 +
mm/swap.c | 1 +
4 files changed, 4 insertions(+)
diff -pruN linux-2.6.17-rc1-mm1/include/linux/mman.h linux-2.6.17-rc1-mm1-test1/include/linux/mman.h
--- linux-2.6.17-rc1-mm1/include/linux/mman.h 2006-03-24 12:40:19.000000000 -0500
+++ linux-2.6.17-rc1-mm1-test1/include/linux/mman.h 2006-04-04 12:53:52.000000000 -0400
@@ -24,6 +24,7 @@ static inline void vm_acct_memory(long p
{
atomic_add(pages, &vm_committed_space);
}
+EXPORT_SYMBOL(vm_acct_memory);
#endif
static inline void vm_unacct_memory(long pages)
diff -pruN linux-2.6.17-rc1-mm1/mm/page_alloc.c linux-2.6.17-rc1-mm1-test1/mm/page_alloc.c
--- linux-2.6.17-rc1-mm1/mm/page_alloc.c 2006-04-04 10:43:57.000000000 -0400
+++ linux-2.6.17-rc1-mm1-test1/mm/page_alloc.c 2006-04-04 12:53:52.000000000 -0400
@@ -52,6 +52,7 @@ EXPORT_SYMBOL(node_possible_map);
unsigned long totalram_pages __read_mostly;
unsigned long totalhigh_pages __read_mostly;
long nr_swap_pages;
+EXPORT_SYMBOL(nr_swap_pages);
int percpu_pagelist_fraction;
static void __free_pages_ok(struct page *page, unsigned int order);
diff -pruN linux-2.6.17-rc1-mm1/mm/slab.c linux-2.6.17-rc1-mm1-test1/mm/slab.c
--- linux-2.6.17-rc1-mm1/mm/slab.c 2006-04-04 10:43:57.000000000 -0400
+++ linux-2.6.17-rc1-mm1-test1/mm/slab.c 2006-04-04 12:53:52.000000000 -0400
@@ -692,6 +692,7 @@ static struct list_head cache_chain;
* SLAB_RECLAIM_ACCOUNT turns this on per-slab
*/
atomic_t slab_reclaim_pages;
+EXPORT_SYMBOL(slab_reclaim_pages);
/*
* chicken and egg problem: delay the per-cpu array allocation
diff -pruN linux-2.6.17-rc1-mm1/mm/swap.c linux-2.6.17-rc1-mm1-test1/mm/swap.c
--- linux-2.6.17-rc1-mm1/mm/swap.c 2006-04-04 10:43:57.000000000 -0400
+++ linux-2.6.17-rc1-mm1-test1/mm/swap.c 2006-04-04 12:53:52.000000000 -0400
@@ -499,6 +499,7 @@ void vm_acct_memory(long pages)
}
preempt_enable();
}
+EXPORT_SYMBOL(vm_acct_memory);
#ifdef CONFIG_HOTPLUG_CPU
^ permalink raw reply
* A test kernel module of OVERCOMMIT_GUESS
From: Hideo AOKI @ 2006-04-05 23:51 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, linux-mm
In-Reply-To: <4434570F.9030507@redhat.com>
[-- Attachment #1: Type: text/plain, Size: 978 bytes --]
Hello Andrew,
This is a kernel module patch which I developed to test my patches.
The module makes a kind of memory pressure situation. After that, the
module tests if the OVERCOMMIT_GUESS detects overcommit.
The module has "mode" option. If you specify "mode=1", the module
tries to allocate pages in the test phase.
Here is the test result when I did "mode=1" test on my machine.
* 2.6.17-rc1-mm1
kernel: Test MAY be <failed>.
kernel: allocation failed: out of vmalloc space - use vmalloc=<size> to increase size.
kernel: allocation failed: out of vmalloc space - use vmalloc=<size> to increase size.
kernel: Test SURELY was <FAILED>.
* 2.6.17-rc1-mm1 + my patches
kernel: Test was <PASSED>.
Unfortunately, this kernel module needs another kernel patch.
I will send it in later e-mail.
Please note that I don't intend to propose to apply the module to
kernel tree.
Best regards,
Hideo Aoki
---
Hideo Aoki, Hitachi Computer Products (America) Inc.
[-- Attachment #2: mm-test_overcommit.patch --]
[-- Type: text/x-patch, Size: 14341 bytes --]
A kernel module to test OVERCOMMIT_GUESS.
lib/Kconfig.debug | 11 +
mm/Makefile | 1
mm/test_overcommit.c | 515 +++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 527 insertions(+)
diff -purN linux-2.6.17-rc1-mm1/lib/Kconfig.debug linux-2.6.17-rc1-mm1-test1/lib/Kconfig.debug
--- linux-2.6.17-rc1-mm1/lib/Kconfig.debug 2006-04-04 10:43:57.000000000 -0400
+++ linux-2.6.17-rc1-mm1-test1/lib/Kconfig.debug 2006-04-04 16:30:31.000000000 -0400
@@ -282,6 +282,17 @@ config RCU_TORTURE_TEST
Say M if you want the RCU torture tests to build as a module.
Say N if you are unsure.
+config OVERCOMMIT_GUESS_TEST
+ tristate "An overcommit guess testing module"
+ depends on DEBUG_KERNEL && X86
+ default n
+ help
+ This option provides a kernel module that can test OVERCOMMIT_GUESS
+ in __vm_enough_memory().
+
+ You should say N or M here. Say M if you want to build the module.
+ Say N if you are unsure.
+
config WANT_EXTRA_DEBUG_INFORMATION
bool
select DEBUG_INFO
diff -purN linux-2.6.17-rc1-mm1/mm/Makefile linux-2.6.17-rc1-mm1-test1/mm/Makefile
--- linux-2.6.17-rc1-mm1/mm/Makefile 2006-04-04 10:43:57.000000000 -0400
+++ linux-2.6.17-rc1-mm1-test1/mm/Makefile 2006-04-04 16:23:09.000000000 -0400
@@ -24,4 +24,5 @@ obj-$(CONFIG_SLAB) += slab.o
obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
obj-$(CONFIG_FS_XIP) += filemap_xip.o
obj-$(CONFIG_MIGRATION) += migrate.o
+obj-$(CONFIG_OVERCOMMIT_GUESS_TEST) += test_overcommit.o
diff -purN linux-2.6.17-rc1-mm1/mm/test_overcommit.c linux-2.6.17-rc1-mm1-test1/mm/test_overcommit.c
--- linux-2.6.17-rc1-mm1/mm/test_overcommit.c 1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.17-rc1-mm1-test1/mm/test_overcommit.c 2006-04-04 16:23:09.000000000 -0400
@@ -0,0 +1,515 @@
+/*
+ * A kernel module for testing OVERCOMMIT_GUESS. ver 0.0.1
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+/*
+ * This kernel module tests the later part of OVERCOMMIT_GUESS algorithm.
+ * To test the algorithm, the module makes a kind of memory pressure situation.
+ * After that, the module tests if the algorithm detects overcommit.
+ *
+ * You can specify by "mode" module option if the module actually tries to
+ * allocate pages in the situation.
+ *
+ * You have to apply a kernel patch to use the module currently, since the
+ * module needs to refer some internal symbols for testing.
+ *
+ * The module was tested on only i386 SMP machines.
+ */
+#include <linux/module.h> /* Needed by all modules */
+#include <linux/moduleparam.h>
+#include <linux/kernel.h> /* Needed for KERN_INFO */
+
+#include <linux/gfp.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/slab.h>
+#include <linux/swap.h>
+#include <linux/vmalloc.h>
+
+#include <asm/kmap_types.h>
+#include <asm/system.h>
+#include <linux/blkdev.h>
+#include <linux/string.h>
+
+/*
+ * Get rid of taint message by declaring code as GPL v2.
+ */
+MODULE_LICENSE("GPL v2");
+
+/*
+ * Module documentation
+ */
+MODULE_AUTHOR("Hideo Aoki");
+MODULE_DESCRIPTION("test module of overcommit guess");
+
+/*
+ * Module parameter(s)
+ */
+enum { MODE_DEFALUT = 0, MODE_DOLASTALLOC = 1 };
+static int mode = MODE_DEFALUT;
+
+module_param(mode, int, S_IRUSR);
+MODULE_PARM_DESC(mode, "test mode. If mode is 1, the module executes actual page allocation in concrete test.");
+
+/*
+ * declarations
+ */
+#define MOD_MM 1 /* modify kernel */
+#define DEF_PRT_LV KERN_DEBUG /* default print level in this mod. */
+
+/*
+ * Page managemnt: We manage allocated pages. When module is unloaded,
+ * the module releases them.
+ */
+struct page_mng_t {
+ struct page *listp; /* list of allocated pages */
+ int zone; /* which zone manage */
+};
+
+/* We use head of allocated pages for managing page list */
+struct mypage_t {
+ struct page *next_page;
+ int order; /* page order */
+};
+
+
+enum {
+ NORMAL, HIGH
+};
+
+static struct page_mng_t low_pg; /* LOWMEM pages management */
+static struct page_mng_t high_pg;/* HIGHMEM pages management */
+static unsigned long committed_pages;/* number of pages committed in the mod.*/
+
+void prepare_test_env(void);
+void final_test(int mode);
+int commit_pages(unsigned long target, struct page_mng_t *mng, int gfp,
+ char *msg);
+int try_to_commit_pages(int order, int gfp, struct page_mng_t *mng,
+ unsigned long *n_alloced);
+int alloc_last_pages(unsigned long npage);
+
+/* allocated page management */
+int page_mng_init(struct page_mng_t *mng, int gfp);
+void page_mng_add(struct page_mng_t *mng, struct page *newp, int order);
+void page_mng_freeall(struct page_mng_t *mng);
+
+/* zone */
+struct zone *get_zone(char *name);
+void print_zone_info(struct zone *zone, char *msg);
+
+
+/*
+ * initialize module and invoke test functions
+ */
+int init_module(void)
+{
+ int ret;
+
+ printk(DEF_PRT_LV "Test module was loaded. <mode %d>\n", mode);
+
+ if (mode != MODE_DEFALUT && mode != MODE_DOLASTALLOC) {
+ printk(KERN_ERR "invalid mode. <mode %d>\n", mode);
+ return 1;
+ }
+
+ /*
+ * making a memory pressure situation
+ */
+ printk(DEF_PRT_LV "init ...");
+ committed_pages = 0;
+ ret = page_mng_init(&low_pg, GFP_KERNEL);
+ if (ret == 1) {
+ printk(KERN_ERR "failed to init lowmem mng\n");
+ return 1;
+ }
+ ret = page_mng_init(&high_pg, GFP_HIGHUSER);
+ if (ret == 1) {
+ printk(KERN_ERR "failed to init highmem mng\n");
+ return 1;
+ }
+ printk(DEF_PRT_LV "done\n");
+
+ prepare_test_env();
+
+ /*
+ * concrete test
+ */
+ printk(DEF_PRT_LV "concrete test ...\n");
+ final_test(mode);
+ printk(DEF_PRT_LV "concrete test ...done.\n");
+
+ /*
+ * A non 0 return means init_module failed; module can't be loaded.
+ */
+ return 0;
+}
+
+
+/*
+ * destructor of module
+ */
+void cleanup_module(void)
+{
+ printk(DEF_PRT_LV "Unloading module ...\n");
+ page_mng_freeall(&low_pg);
+ page_mng_freeall(&high_pg);
+ vm_unacct_memory(committed_pages);
+}
+
+
+/*
+ * To prepare test environment, this function repeat to allocate pages
+ * in ZONE_HIGHMEM and ZONE_NORMAL until the number of free pages is
+ * pages_high in the zone.
+ */
+void prepare_test_env(void)
+{
+ struct zone *high_zone; /* high mem zone */
+ struct zone *normal_zone; /* normal zone */
+ int i;
+ int ret;
+ unsigned long target;
+
+ high_zone = get_zone("HighMem");
+ if (high_zone == NULL) {
+ printk(KERN_ERR "fail to get higmem zone\n");
+ return ;
+ }
+ for (i = 0; i < 100; i++) {
+ if (high_zone->free_pages <= high_zone->pages_high) {
+ printk(DEF_PRT_LV "already satisfied\n");
+ break;
+ }
+
+ spin_lock_irq(&high_zone->lru_lock);
+ target = high_zone->free_pages - high_zone->pages_high;
+ spin_unlock_irq(&high_zone->lru_lock);
+ print_zone_info(high_zone, "HIGH");
+ ret = commit_pages(target, &high_pg, GFP_HIGHUSER, "HighMem");
+ if (ret < 0) {
+ printk(KERN_ERR "error high %i\n", i);
+ goto error;
+ }
+
+ print_zone_info(high_zone, "HIGH");
+ /* printk(DEF_PRT_LV "%i\n", i); */
+ blk_congestion_wait(WRITE, HZ/2);
+ }
+
+ normal_zone = get_zone("Normal");
+ if (high_zone == NULL) {
+ printk(KERN_ERR "fail to get normal zone\n");
+ return ;
+ }
+ for (i = 0; i < 100; i++) {
+ if (normal_zone->free_pages <= normal_zone->pages_high) {
+ printk(DEF_PRT_LV "already satisfied\n");
+ break;
+ }
+
+ spin_lock_irq(&normal_zone->lru_lock);
+ target = normal_zone->free_pages - normal_zone->pages_high;
+ spin_unlock_irq(&normal_zone->lru_lock);
+ print_zone_info(normal_zone, "NORMAL");
+ ret = commit_pages(target, &low_pg, GFP_KERNEL, "Normal");
+ if (ret < 0) {
+ printk(KERN_ERR "error %i\n", i);
+ goto error;
+ }
+
+ print_zone_info(normal_zone, "NORMAL");
+ /* printk(DEF_PRT_LV "%i\n", i); */
+ blk_congestion_wait(WRITE, HZ/2);
+ }
+
+error:
+ return;
+}
+
+/*
+ * main test function
+ */
+void final_test(int mode)
+{
+ int ret;
+ unsigned long n;
+ unsigned long nbuffer;
+ unsigned long ncache;
+ unsigned long nmargin;
+#if MOD_MM
+ unsigned long nslabrec;
+ unsigned long nswap;
+#endif
+ struct sysinfo info;
+
+
+ for (nmargin = 1; nmargin < 100000; nmargin *= 10) {
+ si_meminfo(&info);
+ nbuffer = info.bufferram;
+ ncache = get_page_cache_size();
+#if MOD_MM
+ nslabrec = atomic_read(&slab_reclaim_pages);
+ nswap = nr_swap_pages;
+ n = ncache + nslabrec + nmargin + nswap;
+ printk(DEF_PRT_LV "<buf %lu><cache %lu><slab reclaim %lu><swap %lu> <+ %lu> <target %lu>\n",
+ nbuffer, ncache, nslabrec, nswap, nmargin, n);
+#else
+ n = ncache + nmargin;
+ printk(DEF_PRT_LV "<buf %lu> <cache %lu> <+ %lu> <target %lu>\n",
+ nbuffer, ncache, nmargin, n);
+#endif
+
+ ret = __vm_enough_memory(n, 0);
+ if (ret != 0) {
+ printk(KERN_ERR "Test was <PASSED>.\n");
+ break ;
+ }
+
+ /* unexpected result */
+ committed_pages += n;
+ if (mode == MODE_DOLASTALLOC) {
+ printk(KERN_ERR "Test MAY be <failed>.\n");
+ ret = alloc_last_pages(n);
+ if (ret == 0) {
+ printk(KERN_ERR "Test modeule has problem\n");
+ } else {
+ printk(KERN_ERR "Test SURELY was <FAILED>.\n");
+ break ;
+ }
+ } else {
+ printk(KERN_ERR "Test was <FAILED>\n");
+ }
+ }
+}
+
+int commit_pages(unsigned long target, struct page_mng_t *mng, int gfp,
+ char *msg)
+{
+ int ret;
+ unsigned long total;
+ unsigned long npage;
+
+ if (target == 0 || mng == NULL)
+ goto error;
+
+ /*
+ * try to commit anonymous pages
+ */
+ total = 0;
+ while (total < target) {
+ ret = try_to_commit_pages(0, gfp, mng, &npage);
+ if (ret == 1) {
+ printk(DEF_PRT_LV "%s test stoped. <target %lu>\n",
+ msg, target);
+ return 1;
+ } else if (ret == 0) {
+ total += npage;
+ /* printk(KERN_ERR "p"); */
+ } else if (ret == -1) {
+ printk(KERN_ERR "error %s overcommit.\n", msg);
+ goto error;
+ } else {
+ printk(KERN_ERR "error %s test environment.\n", msg);
+ goto error;
+ }
+ }
+ printk(DEF_PRT_LV "%s <target %lu>, ", msg, target);
+
+ return 0;
+
+ error:
+ return -1;
+}
+
+/*
+ * ret: 1; success (detected overcommit)
+ * 0: success
+ * -1: error (overcommiet was not detected)
+ */
+int try_to_commit_pages(int order, int gfp, struct page_mng_t *mng,
+ unsigned long *n_alloced)
+{
+ int ret;
+ long n_pages;
+ struct page *p;
+
+ n_pages = 1L << order;
+ /* printk(KERN_ERR "<order %d>, <pages %ld>\n,", order, n_pages); */
+
+ *n_alloced = 0;
+
+ ret = __vm_enough_memory(n_pages, 0);
+ if (ret != 0) {
+ printk(KERN_ERR "<order %d>, <pages %ld> ", order, n_pages);
+ printk(KERN_ERR "overcommit was detected.\n");
+ return 1;
+ }
+ committed_pages += n_pages;
+
+ p = alloc_pages(gfp, order);
+ if (p == NULL) {
+ /* error */
+ printk(KERN_ERR "<order %d>, <pages %ld> ", order, n_pages);
+ printk(KERN_ERR "allocation failed\n");
+ return -1;
+ } else {
+ page_mng_add(mng, p, order);
+ *n_alloced += n_pages;
+ /*
+ * printk(KERN_ERR "<order %d>, <pages %ld> <alloced %lu> ",
+ * order, n_pages, *n_alloced);
+ * printk(KERN_ERR " succeed\n");
+ */
+ return 0;
+ }
+}
+
+/*
+ * 0: success, 1: failure
+ */
+int alloc_last_pages(unsigned long npage)
+{
+ int i;
+ int ret;
+ void *mem;
+ struct mypage2_t {
+ struct mypage2_t *next;
+ } *endp, *listp, *p, *nextp;
+
+ /*
+ * allocation scenario 1
+ */
+ mem = vmalloc(npage * PAGE_SIZE);
+ if (mem != NULL) {
+ printk(KERN_ERR "TEST MODULE HAS PROBLEMS.\n");
+ vfree(mem);
+ return 0;
+ }
+
+ /*
+ * allocation scenario 2
+ */
+ for (listp = endp = NULL, i = 0; i < npage; i++) {
+ p = (struct mypage2_t *)vmalloc(PAGE_SIZE);
+ if (p == NULL) {
+ ret = 1;
+ goto release;
+ }
+
+ p->next = NULL;
+ if (listp == NULL)
+ listp = p;
+ else
+ endp->next = p;
+
+ endp = p;
+ }
+
+ printk(KERN_ERR "TEST MODULE HAS PROBLEMS.\n");
+ ret = 0;
+
+release:
+ for ( ; listp != NULL; listp = nextp) {
+ nextp = listp->next;
+ vfree(listp);
+ }
+
+ return ret;
+}
+
+/*
+ * ret: 1: error, 0: success
+ */
+int page_mng_init(struct page_mng_t *mng, int gfp)
+{
+ mng->listp = NULL;
+ if (gfp == GFP_HIGHUSER)
+ mng->zone = HIGH;
+ else if (gfp == GFP_KERNEL || gfp == GFP_USER)
+ mng->zone = NORMAL;
+ else
+ return 1;
+
+ return 0;
+}
+
+void page_mng_add(struct page_mng_t *mng, struct page *newp, int order)
+{
+ struct mypage_t *p;
+
+ if (mng->zone != NORMAL && mng->zone != HIGH) {
+ printk(KERN_ERR "PAGE_MNG: ERROR \n");
+ return ;
+ }
+
+ p = (struct mypage_t *)kmap_atomic(newp, KM_TYPE_NR);
+ p->order = order;
+ p->next_page = mng->listp;
+ mng->listp = newp;
+
+ kunmap_atomic((void *)p, KM_TYPE_NR);
+}
+
+void page_mng_freeall(struct page_mng_t *mng)
+{
+ int order;
+ struct page *next;
+ struct mypage_t *p;
+
+ for ( ; mng->listp != NULL; mng->listp = next) {
+ p = (struct mypage_t *)kmap_atomic(mng->listp, KM_TYPE_NR);
+ next = p->next_page;
+ order = p->order;
+ kunmap_atomic((void *)p, KM_TYPE_NR);
+ __free_pages(mng->listp, order);
+ }
+}
+
+struct zone *get_zone(char *name)
+{
+ struct zone *zone;
+ for_each_zone(zone) {
+ if (strcmp(zone->name, name) == 0)
+ return zone;
+ }
+
+ return NULL;
+}
+
+void print_zone_info(struct zone *zone, char *msg)
+{
+ unsigned long free_pages;
+ unsigned long nr_active;
+ unsigned long nr_inactive;
+ unsigned long present_pages;
+
+ spin_lock_irq(&zone->lru_lock);
+ free_pages = zone->free_pages;
+ nr_active = zone->nr_active;
+ nr_inactive = zone->nr_inactive;
+ present_pages = zone->present_pages;
+ spin_unlock_irq(&zone->lru_lock);
+
+ printk(DEF_PRT_LV "\n%s: <active %lu><inactive %lu><free %lu><sum %lu><present %lu>\n",
+ msg,
+ nr_active,
+ nr_inactive,
+ free_pages,
+ nr_active + nr_inactive + free_pages,
+ present_pages);
+}
^ permalink raw reply
* [patch 3/3] mm: An enhancement of OVERCOMMIT_GUESS
From: Hideo AOKI @ 2006-04-05 23:48 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, linux-mm
[-- Attachment #1: Type: text/plain, Size: 182 bytes --]
There is a copy of __vm_enough_memory() in mm/nommu.c. I believe that
this enhancement is useful for nommu environment too.
---
Hideo Aoki, Hitachi Computer Products (America) Inc.
[-- Attachment #2: mm-consider_rsvpgs-nommu.patch --]
[-- Type: text/x-patch, Size: 1394 bytes --]
This patch is an enhancement of OVERCOMMIT_GUESS algorithm in
__vm_enough_memory() in mm/nommu.c.
When the OVERCOMMIT_GUESS algorithm calculates the number of free
pages, the algorithm subtracts the number of reserved pages from
the result nr_free_pages().
Signed-off-by: Hideo Aoki <haoki@redhat.com>
---
nommu.c | 18 +++++++++++++++---
1 files changed, 15 insertions(+), 3 deletions(-)
diff -purN linux-2.6.17-rc1-mm1/mm/nommu.c linux-2.6.17-rc1-mm1-idea6/mm/nommu.c
--- linux-2.6.17-rc1-mm1/mm/nommu.c 2006-04-04 10:43:30.000000000 -0400
+++ linux-2.6.17-rc1-mm1-idea6/mm/nommu.c 2006-04-04 15:09:24.000000000 -0400
@@ -1147,14 +1147,26 @@ int __vm_enough_memory(long pages, int c
* only call if we're about to fail.
*/
n = nr_free_pages();
+
+ /*
+ * Leave reserved pages. The pages are not for anonymous pages.
+ */
+ if (n <= totalreserve_pages)
+ goto error;
+ else
+ n -= totalreserve_pages;
+
+ /*
+ * Leave the last 3% for root
+ */
if (!cap_sys_admin)
n -= n / 32;
free += n;
if (free > pages)
return 0;
- vm_unacct_memory(pages);
- return -ENOMEM;
+
+ goto error;
}
allowed = totalram_pages * sysctl_overcommit_ratio / 100;
@@ -1175,7 +1187,7 @@ int __vm_enough_memory(long pages, int c
*/
if (atomic_read(&vm_committed_space) < (long)allowed)
return 0;
-
+error:
vm_unacct_memory(pages);
return -ENOMEM;
^ permalink raw reply
* [patch 2/3] mm: An enhancement of OVERCOMMIT_GUESS
From: Hideo AOKI @ 2006-04-05 23:48 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, linux-mm
[-- Attachment #1: Type: text/plain, Size: 187 bytes --]
This patch is the main part of this enhancement.
Additionally, the patch includes better error handling in __vm_enough_memory().
---
Hideo Aoki, Hitachi Computer Products (America) Inc.
[-- Attachment #2: mm-consider_rsvpgs.patch --]
[-- Type: text/x-patch, Size: 1380 bytes --]
This patch is an enhancement of OVERCOMMIT_GUESS algorithm in
__vm_enough_memory() in mm/mmap.c.
When the OVERCOMMIT_GUESS algorithm calculates the number of free
pages, the algorithm subtracts the number of reserved pages from
the result nr_free_pages().
Signed-off-by: Hideo Aoki <haoki@redhat.com>
---
mmap.c | 18 +++++++++++++++---
1 files changed, 15 insertions(+), 3 deletions(-)
diff -purN linux-2.6.17-rc1-mm1/mm/mmap.c linux-2.6.17-rc1-mm1-idea6/mm/mmap.c
--- linux-2.6.17-rc1-mm1/mm/mmap.c 2006-04-04 10:43:57.000000000 -0400
+++ linux-2.6.17-rc1-mm1-idea6/mm/mmap.c 2006-04-04 14:56:51.000000000 -0400
@@ -121,14 +121,26 @@ int __vm_enough_memory(long pages, int c
* only call if we're about to fail.
*/
n = nr_free_pages();
+
+ /*
+ * Leave reserved pages. The pages are not for anonymous pages.
+ */
+ if (n <= totalreserve_pages)
+ goto error;
+ else
+ n -= totalreserve_pages;
+
+ /*
+ * Leave the last 3% for root
+ */
if (!cap_sys_admin)
n -= n / 32;
free += n;
if (free > pages)
return 0;
- vm_unacct_memory(pages);
- return -ENOMEM;
+
+ goto error;
}
allowed = (totalram_pages - hugetlb_total_pages())
@@ -150,7 +162,7 @@ int __vm_enough_memory(long pages, int c
*/
if (atomic_read(&vm_committed_space) < (long)allowed)
return 0;
-
+error:
vm_unacct_memory(pages);
return -ENOMEM;
^ permalink raw reply
* [patch 1/3] mm: An enhancement of OVERCOMMIT_GUESS
From: Hideo AOKI @ 2006-04-05 23:47 UTC (permalink / raw)
To: akpm; +Cc: linux-kernel, linux-mm
[-- Attachment #1: Type: text/plain, Size: 562 bytes --]
Hello Andrew,
Could you apply my patches to your tree?
These patches are an enhancement of OVERCOMMIT_GUESS algorithm in
__vm_enough_memory(). The detailed description is in attached patch.
Actually, these are the revised patch which I sent to lkml in the last
year.
http://marc.theaimsgroup.com/?l=linux-kernel&m=112993489022427&w=2
I wrote a test kernel module to show the result of the patches.
For your information, I also would like to send the module in later e-mail.
Best regards,
Hideo Aoki
---
Hideo Aoki, Hitachi Computer Products (America) Inc.
[-- Attachment #2: mm-add-totalreserve_pages.patch --]
[-- Type: text/x-patch, Size: 4960 bytes --]
These patches are an enhancement of OVERCOMMIT_GUESS algorithm in
__vm_enough_memory().
- why the kernel needed patching
When the kernel can't allocate anonymous pages in practice, currnet
OVERCOMMIT_GUESS could return success. This implementation might be
the cause of oom kill in memory pressure situation.
If the Linux runs with page reservation features like
/proc/sys/vm/lowmem_reserve_ratio and without swap region, I think
the oom kill occurs easily.
- the overall design approach in the patch
When the OVERCOMMET_GUESS algorithm calculates number of free pages,
the reserved free pages are regarded as non-free pages.
This change helps to avoid the pitfall that the number of free pages
become less than the number which the kernel tries to keep free.
- testing results
I tested the patches using my test kernel module.
If the patches aren't applied to the kernel, __vm_enough_memory()
returns success in the situation but autual page allocation is
failed.
On the other hand, if the patches are applied to the kernel, memory
allocation failure is avoided since __vm_enough_memory() returns
failure in the situation.
I checked that on i386 SMP 16GB memory machine. I haven't tested on
nommu environment currently.
- changelog
v5:
- updated to 2.6.17-rc1-mm1
- did more strict tests.
- added the enhancement to mm/nommu.c too
v4:
- dealing with pages_high as reserved pages
- updated the code for 2.6.14-rc4-mm1
v3 (private):
- enhanced error handling in __vm_enough_memory
- fixed an issue related calculation of totalreserve_pages
v2 (private):
- fixed error handling bug
- updated test results
- updated the code for 2.6.14-rc2-mm2
This patch adds totalreserve_pages for __vm_enough_memory().
Calculate_totalreserve_pages() checks maximum lowmem_reserve pages and
pages_high in each zone. Finally, the function stores the sum of each
zone to totalreserve_pages.
The totalreserve_pages is calculated when the VM is initilized.
And the variable is updated when /proc/sys/vm/lowmem_reserve_raito
or /proc/sys/vm/min_free_kbytes are changed.
Signed-off-by: Hideo Aoki <haoki@redhat.com>
---
include/linux/swap.h | 1 +
mm/page_alloc.c | 39 +++++++++++++++++++++++++++++++++++++++
2 files changed, 40 insertions(+)
diff -purN linux-2.6.17-rc1-mm1/include/linux/swap.h linux-2.6.17-rc1-mm1-idea6/include/linux/swap.h
--- linux-2.6.17-rc1-mm1/include/linux/swap.h 2006-04-04 10:43:57.000000000 -0400
+++ linux-2.6.17-rc1-mm1-idea6/include/linux/swap.h 2006-04-04 15:13:26.000000000 -0400
@@ -155,6 +155,7 @@ extern void swapin_readahead(swp_entry_t
/* linux/mm/page_alloc.c */
extern unsigned long totalram_pages;
extern unsigned long totalhigh_pages;
+extern unsigned long totalreserve_pages;
extern long nr_swap_pages;
extern unsigned int nr_free_pages(void);
extern unsigned int nr_free_pages_pgdat(pg_data_t *pgdat);
diff -purN linux-2.6.17-rc1-mm1/mm/page_alloc.c linux-2.6.17-rc1-mm1-idea6/mm/page_alloc.c
--- linux-2.6.17-rc1-mm1/mm/page_alloc.c 2006-04-04 10:43:57.000000000 -0400
+++ linux-2.6.17-rc1-mm1-idea6/mm/page_alloc.c 2006-04-04 15:13:26.000000000 -0400
@@ -51,6 +51,7 @@ nodemask_t node_possible_map __read_most
EXPORT_SYMBOL(node_possible_map);
unsigned long totalram_pages __read_mostly;
unsigned long totalhigh_pages __read_mostly;
+unsigned long totalreserve_pages __read_mostly;
long nr_swap_pages;
int percpu_pagelist_fraction;
@@ -2548,6 +2549,38 @@ void __init page_alloc_init(void)
}
/*
+ * calculate_totalreserve_pages - called when sysctl_lower_zone_reserve_ratio
+ * or min_free_kbytes changes.
+ */
+static void calculate_totalreserve_pages(void)
+{
+ struct pglist_data *pgdat;
+ unsigned long reserve_pages = 0;
+ int i, j;
+
+ for_each_online_pgdat(pgdat) {
+ for (i = 0; i < MAX_NR_ZONES; i++) {
+ struct zone *zone = pgdat->node_zones + i;
+ unsigned long max = 0;
+
+ /* Find valid and maximum lowmem_reserve in the zone */
+ for (j = i; j < MAX_NR_ZONES; j++) {
+ if (zone->lowmem_reserve[j] > max)
+ max = zone->lowmem_reserve[j];
+ }
+
+ /* we treat pages_high as reserved pages. */
+ max += zone->pages_high;
+
+ if (max > zone->present_pages)
+ max = zone->present_pages;
+ reserve_pages += max;
+ }
+ }
+ totalreserve_pages = reserve_pages;
+}
+
+/*
* setup_per_zone_lowmem_reserve - called whenever
* sysctl_lower_zone_reserve_ratio changes. Ensures that each zone
* has a correct pages reserved value, so an adequate number of
@@ -2578,6 +2611,9 @@ static void setup_per_zone_lowmem_reserv
}
}
}
+
+ /* update totalreserve_pages */
+ calculate_totalreserve_pages();
}
/*
@@ -2632,6 +2668,9 @@ void setup_per_zone_pages_min(void)
zone->pages_high = zone->pages_min + tmp / 2;
spin_unlock_irqrestore(&zone->lru_lock, flags);
}
+
+ /* update totalreserve_pages */
+ calculate_totalreserve_pages();
}
/*
^ permalink raw reply
* Re: [Lhms-devel] [RFC 0/6] Swapless Page Migration V1: Overview
From: Lee Schermerhorn @ 2006-04-05 18:52 UTC (permalink / raw)
To: Christoph Lameter
Cc: linux-mm, lhms-devel, Hirokazu Takahashi, Marcelo Tosatti,
KAMEZAWA Hiroyuki
In-Reply-To: <Pine.LNX.4.64.0604051032130.1768@schroedinger.engr.sgi.com>
On Wed, 2006-04-05 at 10:43 -0700, Christoph Lameter wrote:
> On Wed, 5 Apr 2006, Lee Schermerhorn wrote:
>
> > > We never allow a faulting in of the new page before migration is
> > > complete. The replacing of the swap ptes with real ptes was always done
> > > after migration was complete. Same thing here.
> >
> > Unless we're talking about different things [happens], my migrate-on-
> > fault patches do this. Pages are unmapped from ptes and left hanging in
> > the cache until some task touches them. Then the migration occurs, if
>
> Well you can only umap file backed pages. These are still working the same
> way. Anonymous pages can only be remapped in a different way not unmapped.
> "unmap" of anonymous pages in todays kernels really means remap to swap
> space.
My point exactly. And to get them to migrate on fault [which I want to
do], I need to unmap them and leave them that way until some task
touches them.
>
>
> If you put the anonymous pages on swap then you can still have the old
> behavior but then you would require swap space.
Or a migration cache that behaves like swap, but doesn't actually
reserve disk space.
Note: my traces show that the current [2.6.17-rc1] migration mechanism
only uses one swap entry at a time, per running instance of migration.
So, I don't think there is a hurry to eliminate this usage for "direct
migration". If we accept migrate on fault, then pages can lay around in
the swap cache for some time. That would motivate us to investigate a
solution that doesn't reserve swap.
> > In any case, I don't think we want to be walking reverse maps and other
> > task's pte's in one task's page fault path. Perhaps "migrate-on-fault"
> > and "auto-migration" are not going to go anywhere, but if they do, we'll
> > need something like the existing swap/migration cache behavior, where
> > the temporary ptes reference a single [reference counted] cache entry
> > that points at either the old or new page.
>
> No we certainly do not want to walk reverse maps in critical sections of
> the code.
>
> I think the opportunistic lazy migration that we were talking about before
> would be fine with this scheme. You just check the refcount during the
> fault and then migrate the page if this would establish the first
> mapcount.
The pages must exist in a cache with mapcount==0 at fault time [swap or
migration cache for anon pages] for this to work, right?
>
> Pushing pages into the migration cache from the scheduler in order to
> migrate them later when references are to be reestablished will no longer
> work.
:-(, I know...
>
> Would not swap be a more appropriate mechanism there? I mean the
> functionality that you want is almost exactly the same as swap. The
> checking of the mapcounts can then work the same way as opportunistic lazy
> migration.
Yes. We've discussed this before. Swap works just fine for this. My
current migrate-on-fault and auto-migration series does not change this.
The issue that we still need to work out [assuming these patches go
forward] is whether it's perferable to let such pages hang around in the
swap cache tying up swap device space that they never intend to use, or
to implement a pseudo-swap device like the migration cache to hold the
pte entries of unmapped anon pages. I put the migration cache work on
hold to work up the aforementioned patch series. I could do this,
because it works with swap. If you remove the use of swap in
try_to_unmap(), etc., my patches would either have to put it back or
ressurect the migration cache sooner than planned. As it stands,
migrate-on-fault is a relatively small change to the in-kernel migration
mechanism.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Some ideas on lazy migration with swapless migration
From: Christoph Lameter @ 2006-04-05 18:17 UTC (permalink / raw)
To: Lee Schermerhorn
Cc: linux-mm, lhms-devel, Hirokazu Takahashi, Marcelo Tosatti,
KAMEZAWA Hiroyuki
In-Reply-To: <1144256328.5203.36.camel@localhost.localdomain>
I think it is possible to do lazy migration without having to resort to a
migration cache by either
A. Forbidding write to the page. The corresponding invocation to
to do_wp_page() on a write attempt can then be used to migrate the
page. However, this would only work for write attempts.
B. Clear the present bit. The corresponding invocation of do_swap_page
may check for the type of pte and do the lazy migration and then set
the present bit again.
Hmm... B. would be an even better way to replace SWP_TYPE_MIGRATION and
not use the swap code at all (which would simply take a lock on the page
and redo the fault after releasing the lock) but it would require some
work to get arch support for clearing and setting the present bit.
However, there are only a few arches supporting NUMA and migration. So it
should be doable.
Maybe the idea with the present bit can be used to further simplify
migration:
1. Before migration clear all the present bits which guarantees
that the faults will stall in do_swap_page() since the page is
locked. No need to reduce the mapcount since the ptes are still there
and can be switched back to working condition by do_swap_page().
2. do_swap_page() will lock the page (and therefore stall during
migration). After the page lock is obtained we check the present bit if
it is now set then redo the fault. If not then do lazy migration if
needed and set the bit.
3. Migration will move the page and then replace ptes with cleared
present bits with ptes pointing to the new page with the present bit
enabled.
Since we do not reduce the mapcount, we can use that mapcount to verify
that it is still safe to get to the corresponding anonymous vma for
anonymous pages. Some portions of the vm would have to be fixed up to know
how to deal with valid ptes that are not present (fork and unmap code).
For file backed pages we would not have to remove the references anymore.
We can migrate in the same way as the anonymous pages. We just need to
make sure to first change the mapping. That would be an important feature
for us because it preserves the page state in a better way. We could also
preserve the dirty bits and accessed bits in the pte.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [Lhms-devel] [RFC 0/6] Swapless Page Migration V1: Overview
From: Christoph Lameter @ 2006-04-05 17:43 UTC (permalink / raw)
To: Lee Schermerhorn
Cc: linux-mm, lhms-devel, Hirokazu Takahashi, Marcelo Tosatti,
KAMEZAWA Hiroyuki
In-Reply-To: <1144256328.5203.36.camel@localhost.localdomain>
On Wed, 5 Apr 2006, Lee Schermerhorn wrote:
> > We never allow a faulting in of the new page before migration is
> > complete. The replacing of the swap ptes with real ptes was always done
> > after migration was complete. Same thing here.
>
> Unless we're talking about different things [happens], my migrate-on-
> fault patches do this. Pages are unmapped from ptes and left hanging in
> the cache until some task touches them. Then the migration occurs, if
Well you can only umap file backed pages. These are still working the same
way. Anonymous pages can only be remapped in a different way not unmapped.
"unmap" of anonymous pages in todays kernels really means remap to swap
space.
If you put the anonymous pages on swap then you can still have the old
behavior but then you would require swap space.
> In any case, I don't think we want to be walking reverse maps and other
> task's pte's in one task's page fault path. Perhaps "migrate-on-fault"
> and "auto-migration" are not going to go anywhere, but if they do, we'll
> need something like the existing swap/migration cache behavior, where
> the temporary ptes reference a single [reference counted] cache entry
> that points at either the old or new page.
No we certainly do not want to walk reverse maps in critical sections of
the code.
I think the opportunistic lazy migration that we were talking about before
would be fine with this scheme. You just check the refcount during the
fault and then migrate the page if this would establish the first
mapcount.
Pushing pages into the migration cache from the scheduler in order to
migrate them later when references are to be reestablished will no longer
work.
Would not swap be a more appropriate mechanism there? I mean the
functionality that you want is almost exactly the same as swap. The
checking of the mapcounts can then work the same way as opportunistic lazy
migration.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [Lhms-devel] [RFC 0/6] Swapless Page Migration V1: Overview
From: Lee Schermerhorn @ 2006-04-05 16:58 UTC (permalink / raw)
To: Christoph Lameter
Cc: linux-mm, lhms-devel, Hirokazu Takahashi, Marcelo Tosatti,
KAMEZAWA Hiroyuki
In-Reply-To: <Pine.LNX.4.64.0604050925110.1387@schroedinger.engr.sgi.com>
On Wed, 2006-04-05 at 09:28 -0700, Christoph Lameter wrote:
> On Wed, 5 Apr 2006, Lee Schermerhorn wrote:
>
> > Does this approach still allow "migrate-on-fault" for anon pages?
>
> I am not aware of something that would be in the way.
>
> > Especially, in the case where the migrating page has >1 pte referencing
> > it? How will the fault handler find all of the pte's referencing the
> > old page? Actually, I don't think we'd want to burden the task whose
>
> The fault handler can find these via the reverse maps.
>
> > fault caused the migration with finding and replacing and replacing all
> > pte's referecing the old page. Using a real cache, this isn't a problem
> > because we replace the old page with a new one in the cache, and the
> > cache ptes reference the cache entry. Tasks are free to fault in a real
> > pte for the new page at any time. I'd hate to lose this capability. I
> > believe that this is one of the reasons that Marcello used a real idr-
> > based cache for the migration cache.
>
> We never allow a faulting in of the new page before migration is
> complete. The replacing of the swap ptes with real ptes was always done
> after migration was complete. Same thing here.
Unless we're talking about different things [happens], my migrate-on-
fault patches do this. Pages are unmapped from ptes and left hanging in
the cache until some task touches them. Then the migration occurs, if
mapcount+policy so indicate, the new page replaces the old page in the
cache, the fault handler inserts a real pte referencing the new page and
removes one reference from the cache entry. In the case of migration
cache, if this was the last pte reference, the entry is freed. For the
swap cache, the page still references the swap entry and will until
explicitly removed. If other task's ptes reference the cache entry, it
remains available, pointing at the new page, to resolve subsequent page
faults by those tasks.
Series starts with:
http://marc.theaimsgroup.com/?l=linux-mm&m=114200021231527&w=4
I've been reworking these patches against your reorganized migration
code in 2.6.17-rc1. I planned to resubmit after refreshing against 17-
rc1-mm1. Unfortunately, 17-rc1-mm1 doesn't boot on my platform [sans
any of my patches], so now I'm investigating that...
In any case, I don't think we want to be walking reverse maps and other
task's pte's in one task's page fault path. Perhaps "migrate-on-fault"
and "auto-migration" are not going to go anywhere, but if they do, we'll
need something like the existing swap/migration cache behavior, where
the temporary ptes reference a single [reference counted] cache entry
that points at either the old or new page.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [Lhms-devel] [RFC 0/6] Swapless Page Migration V1: Overview
From: Christoph Lameter @ 2006-04-05 16:28 UTC (permalink / raw)
To: Lee Schermerhorn
Cc: linux-mm, lhms-devel, Hirokazu Takahashi, Marcelo Tosatti,
KAMEZAWA Hiroyuki
In-Reply-To: <1144248362.5203.22.camel@localhost.localdomain>
On Wed, 5 Apr 2006, Lee Schermerhorn wrote:
> Does this approach still allow "migrate-on-fault" for anon pages?
I am not aware of something that would be in the way.
> Especially, in the case where the migrating page has >1 pte referencing
> it? How will the fault handler find all of the pte's referencing the
> old page? Actually, I don't think we'd want to burden the task whose
The fault handler can find these via the reverse maps.
> fault caused the migration with finding and replacing and replacing all
> pte's referecing the old page. Using a real cache, this isn't a problem
> because we replace the old page with a new one in the cache, and the
> cache ptes reference the cache entry. Tasks are free to fault in a real
> pte for the new page at any time. I'd hate to lose this capability. I
> believe that this is one of the reasons that Marcello used a real idr-
> based cache for the migration cache.
We never allow a faulting in of the new page before migration is
complete. The replacing of the swap ptes with real ptes was always done
after migration was complete. Same thing here.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [Lhms-devel] [RFC 0/6] Swapless Page Migration V1: Overview
From: Lee Schermerhorn @ 2006-04-05 14:46 UTC (permalink / raw)
To: Christoph Lameter
Cc: linux-mm, lhms-devel, Hirokazu Takahashi, Marcelo Tosatti,
KAMEZAWA Hiroyuki
In-Reply-To: <20060404065739.24532.95451.sendpatchset@schroedinger.engr.sgi.com>
On Mon, 2006-04-03 at 23:57 -0700, Christoph Lameter wrote:
> Swapless Page migration
>
> Currently page migration is depending on the ability to assign swap entries
> to pages. This means that page migration will not work without swap although
> that swap space is never used.
>
> This patchset removes that dependency by introducing a special type of
> swap entry that encodes a pfn number of the page being migrated. If that
> swap pte is encountered then do_swap_page() will simply wait for the page
> to become unlocked again (meaning page migration is complete) and then refetch
> the pte. The special type of swap entry is only in use while the page to be
> migrated is locked and therefore we can hopefully get away with just a few
> supporting functions.
>
> To some extend this covers the same ground as Lee's and Marcelo's migration
> cache. However, I hope that this approach simplifies things without opening
> up any holes. Please check.
>
Christoph:
Does this approach still allow "migrate-on-fault" for anon pages?
Especially, in the case where the migrating page has >1 pte referencing
it? How will the fault handler find all of the pte's referencing the
old page? Actually, I don't think we'd want to burden the task whose
fault caused the migration with finding and replacing and replacing all
pte's referecing the old page. Using a real cache, this isn't a problem
because we replace the old page with a new one in the cache, and the
cache ptes reference the cache entry. Tasks are free to fault in a real
pte for the new page at any time. I'd hate to lose this capability. I
believe that this is one of the reasons that Marcello used a real idr-
based cache for the migration cache.
Lee
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* [Patch:004/004] wait_table and zonelist initializing for memory hotadd (update zonelists)
From: Yasunori Goto @ 2006-04-05 11:01 UTC (permalink / raw)
To: Andrew Morton; +Cc: Linux Kernel ML, linux-mm
In-Reply-To: <20060405192737.3C3F.Y-GOTO@jp.fujitsu.com>
In current code, zonelist is considered to be build once, no modification.
But MemoryHotplug can add new zone/pgdat. It must be updated.
This patch modifies build_all_zonelists().
By this, build_all_zonelist() can reconfig pgdat's zonelists.
To update them safety, this patch use stop_machine_run().
Other cpus don't touch among updating them by using it.
In previous version (V2), kernel updated them after zone initialization.
But present_page of its new zone is still 0, because online_page()
is not called yet at this time.
Build_zonelists() checks present_pages to find present zone.
It was too early. So, I changed it after online_pages().
Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com>
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
mm/memory_hotplug.c | 12 ++++++++++++
mm/page_alloc.c | 26 +++++++++++++++++++++-----
2 files changed, 33 insertions(+), 5 deletions(-)
Index: pgdat10/mm/page_alloc.c
===================================================================
--- pgdat10.orig/mm/page_alloc.c 2006-04-04 20:42:51.000000000 +0900
+++ pgdat10/mm/page_alloc.c 2006-04-04 20:42:52.000000000 +0900
@@ -37,6 +37,7 @@
#include <linux/nodemask.h>
#include <linux/vmalloc.h>
#include <linux/mempolicy.h>
+#include <linux/stop_machine.h>
#include <asm/tlbflush.h>
#include "internal.h"
@@ -1762,14 +1763,29 @@ static void __init build_zonelists(pg_da
#endif /* CONFIG_NUMA */
-void __init build_all_zonelists(void)
+/* return values int ....just for stop_machine_run() */
+static int __meminit __build_all_zonelists(void *dummy)
{
- int i;
+ int nid;
+ for_each_online_node(nid)
+ build_zonelists(NODE_DATA(nid));
+ return 0;
+}
+
+void __meminit build_all_zonelists(void)
+{
+ if (system_state == SYSTEM_BOOTING) {
+ __build_all_zonelists(0);
+ cpuset_init_current_mems_allowed();
+ } else {
+ /* we have to stop all cpus to guaranntee there is no user
+ of zonelist */
+ stop_machine_run(__build_all_zonelists, NULL, NR_CPUS);
+ /* cpuset refresh routine should be here */
+ }
- for_each_online_node(i)
- build_zonelists(NODE_DATA(i));
printk("Built %i zonelists\n", num_online_nodes());
- cpuset_init_current_mems_allowed();
+
}
/*
Index: pgdat10/mm/memory_hotplug.c
===================================================================
--- pgdat10.orig/mm/memory_hotplug.c 2006-04-04 20:42:49.000000000 +0900
+++ pgdat10/mm/memory_hotplug.c 2006-04-04 20:42:52.000000000 +0900
@@ -123,6 +123,7 @@ int online_pages(unsigned long pfn, unsi
unsigned long flags;
unsigned long onlined_pages = 0;
struct zone *zone;
+ int need_zonelists_rebuild = 0;
/*
* This doesn't need a lock to do pfn_to_page().
@@ -135,6 +136,14 @@ int online_pages(unsigned long pfn, unsi
grow_pgdat_span(zone->zone_pgdat, pfn, pfn + nr_pages);
pgdat_resize_unlock(zone->zone_pgdat, &flags);
+ /*
+ * If this zone is not populated, then it is not in zonelist.
+ * This means the page allocator ignores this zone.
+ * So, zonelist must be updated after online.
+ */
+ if (!populated_zone(zone))
+ need_zonelists_rebuild = 1;
+
for (i = 0; i < nr_pages; i++) {
struct page *page = pfn_to_page(pfn + i);
online_page(page);
@@ -145,5 +154,8 @@ int online_pages(unsigned long pfn, unsi
setup_per_zone_pages_min();
+ if (need_zonelists_rebuild)
+ build_all_zonelists();
+
return 0;
}
--
Yasunori Goto
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* [Patch:003/004] wait_table and zonelist initializing for memory hotadd (wait_table initialization)
From: Yasunori Goto @ 2006-04-05 11:01 UTC (permalink / raw)
To: Andrew Morton; +Cc: Linux Kernel ML, linux-mm
In-Reply-To: <20060405192737.3C3F.Y-GOTO@jp.fujitsu.com>
Wait_table is initialized according to zone size at boot time.
But, we cannot know the maixmum zone size when memory hotplug is enabled.
It can be changed.... And resizing of wait_table is hard.
So kernel allocate and initialzie wait_table as its maximum size.
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com>
mm/page_alloc.c | 45 +++++++++++++++++++++++++++++++++++++++------
1 files changed, 39 insertions(+), 6 deletions(-)
Index: pgdat10/mm/page_alloc.c
===================================================================
--- pgdat10.orig/mm/page_alloc.c 2006-04-05 16:04:22.000000000 +0900
+++ pgdat10/mm/page_alloc.c 2006-04-05 16:10:17.000000000 +0900
@@ -1785,6 +1785,7 @@ void __init build_all_zonelists(void)
*/
#define PAGES_PER_WAITQUEUE 256
+#ifdef CONFIG_MEMORY_HOTPLUG
static inline unsigned long wait_table_size(unsigned long pages)
{
unsigned long size = 1;
@@ -1803,6 +1804,17 @@ static inline unsigned long wait_table_s
return max(size, 4UL);
}
+#else
+/*
+ * XXX: Because zone size might be changed by hot-add,
+ * It is hard to determin suitable size for wait_table as traditional.
+ * So, we use maximum size now.
+ */
+static inline unsigned long wait_table_size(unsigned long pages)
+{
+ return 4096UL;
+}
+#endif
/*
* This is an integer logarithm so that shifts can be used later
@@ -2071,10 +2083,11 @@ void __init setup_per_cpu_pageset(void)
#endif
static __meminit
-void zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
+int zone_wait_table_init(struct zone *zone, unsigned long zone_size_pages)
{
int i;
struct pglist_data *pgdat = zone->zone_pgdat;
+ size_t alloc_size;
/*
* The per-page waitqueue mechanism uses hashed waitqueues
@@ -2082,12 +2095,30 @@ void zone_wait_table_init(struct zone *z
*/
zone->wait_table_size = wait_table_size(zone_size_pages);
zone->wait_table_bits = wait_table_bits(zone->wait_table_size);
- zone->wait_table = (wait_queue_head_t *)
- alloc_bootmem_node(pgdat, zone->wait_table_size
- * sizeof(wait_queue_head_t));
+ alloc_size = zone->wait_table_size * sizeof(wait_queue_head_t);
+
+ if (system_state == SYSTEM_BOOTING) {
+ zone->wait_table = (wait_queue_head_t *)
+ alloc_bootmem_node(pgdat, alloc_size);
+ } else {
+ /*
+ * XXX: This case means that a zone whose size was 0 gets new
+ * memory by memory hot-add.
+ * But, this may be the case that "new node" is hotadded.
+ * If its case, vmalloc() will not get this new node's
+ * memory. Because this wait_table must be initialized
+ * to use this new node itself too.
+ * To use this new node's memory, further consideration
+ * will be necessary.
+ */
+ zone->wait_table = (wait_queue_head_t *)vmalloc(alloc_size);
+ }
+ if (!zone->wait_table)
+ return -ENOMEM;
for(i = 0; i < zone->wait_table_size; ++i)
init_waitqueue_head(zone->wait_table + i);
+ return 0;
}
static __meminit void zone_pcp_init(struct zone *zone)
@@ -2114,8 +2145,10 @@ __meminit int init_currently_empty_zone(
unsigned long size)
{
struct pglist_data *pgdat = zone->zone_pgdat;
-
- zone_wait_table_init(zone, size);
+ int ret;
+ ret = zone_wait_table_init(zone, size);
+ if (ret)
+ return ret;
pgdat->nr_zones = zone_idx(zone) + 1;
zone->zone_start_pfn = zone_start_pfn;
--
Yasunori Goto
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* [Patch:002/004] wait_table and zonelist initializing for memory hotadd (add return code for init_current_empty_zone)
From: Yasunori Goto @ 2006-04-05 11:01 UTC (permalink / raw)
To: Andrew Morton; +Cc: Linux Kernel ML, linux-mm
In-Reply-To: <20060405192737.3C3F.Y-GOTO@jp.fujitsu.com>
When add_zone() is called against empty zone (not populated zone),
we have to initialize the zone which didn't initialize at boot time.
But, init_currently_empty_zone() may fail due to allocation of
wait table. So, this patch is to catch its error code.
Changes against wait_table is in the next patch.
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Signed-off-by: Yasunori Goto <y-goto@jp.fujitsu.com>
include/linux/mmzone.h | 3 +++
mm/memory_hotplug.c | 15 +++++++++++++--
mm/page_alloc.c | 11 ++++++++---
3 files changed, 24 insertions(+), 5 deletions(-)
Index: pgdat10/mm/page_alloc.c
===================================================================
--- pgdat10.orig/mm/page_alloc.c 2006-03-31 14:43:33.000000000 +0900
+++ pgdat10/mm/page_alloc.c 2006-03-31 15:50:08.000000000 +0900
@@ -2109,8 +2109,9 @@ static __meminit void zone_pcp_init(stru
zone->name, zone->present_pages, batch);
}
-static __meminit void init_currently_empty_zone(struct zone *zone,
- unsigned long zone_start_pfn, unsigned long size)
+__meminit int init_currently_empty_zone(struct zone *zone,
+ unsigned long zone_start_pfn,
+ unsigned long size)
{
struct pglist_data *pgdat = zone->zone_pgdat;
@@ -2122,6 +2123,8 @@ static __meminit void init_currently_emp
memmap_init(size, pgdat->node_id, zone_idx(zone), zone_start_pfn);
zone_init_free_lists(pgdat, zone, zone->spanned_pages);
+
+ return 0;
}
/*
@@ -2136,6 +2139,7 @@ static void __init free_area_init_core(s
unsigned long j;
int nid = pgdat->node_id;
unsigned long zone_start_pfn = pgdat->node_start_pfn;
+ int ret;
pgdat_resize_init(pgdat);
pgdat->nr_zones = 0;
@@ -2177,7 +2181,8 @@ static void __init free_area_init_core(s
continue;
zonetable_add(zone, nid, j, zone_start_pfn, size);
- init_currently_empty_zone(zone, zone_start_pfn, size);
+ ret = init_currently_empty_zone(zone, zone_start_pfn, size);
+ BUG_ON(ret);
zone_start_pfn += size;
}
}
Index: pgdat10/mm/memory_hotplug.c
===================================================================
--- pgdat10.orig/mm/memory_hotplug.c 2006-03-22 17:25:06.000000000 +0900
+++ pgdat10/mm/memory_hotplug.c 2006-03-31 15:50:08.000000000 +0900
@@ -26,7 +26,7 @@
extern void zonetable_add(struct zone *zone, int nid, int zid, unsigned long pfn,
unsigned long size);
-static void __add_zone(struct zone *zone, unsigned long phys_start_pfn)
+static int __add_zone(struct zone *zone, unsigned long phys_start_pfn)
{
struct pglist_data *pgdat = zone->zone_pgdat;
int nr_pages = PAGES_PER_SECTION;
@@ -34,8 +34,15 @@ static void __add_zone(struct zone *zone
int zone_type;
zone_type = zone - pgdat->node_zones;
+ if (!populated_zone(zone)) {
+ int ret = 0;
+ ret = init_currently_empty_zone(zone, phys_start_pfn, nr_pages);
+ if (ret < 0)
+ return ret;
+ }
memmap_init_zone(nr_pages, nid, zone_type, phys_start_pfn);
zonetable_add(zone, nid, zone_type, phys_start_pfn, nr_pages);
+ return 0;
}
extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn,
@@ -50,7 +57,11 @@ static int __add_section(struct zone *zo
if (ret < 0)
return ret;
- __add_zone(zone, phys_start_pfn);
+ ret = __add_zone(zone, phys_start_pfn);
+
+ if (ret < 0)
+ return ret;
+
return register_new_memory(__pfn_to_section(phys_start_pfn));
}
Index: pgdat10/include/linux/mmzone.h
===================================================================
--- pgdat10.orig/include/linux/mmzone.h 2006-03-31 14:43:32.000000000 +0900
+++ pgdat10/include/linux/mmzone.h 2006-03-31 15:50:08.000000000 +0900
@@ -332,6 +332,9 @@ void wakeup_kswapd(struct zone *zone, in
int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
int classzone_idx, int alloc_flags);
+extern int init_currently_empty_zone(struct zone *zone, unsigned long start_pfn,
+ unsigned long size);
+
#ifdef CONFIG_HAVE_MEMORY_PRESENT
void memory_present(int nid, unsigned long start, unsigned long end);
#else
--
Yasunori Goto
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox