Skip to contentSkip to conversation

Pzone based CKRM memory resource controller

PATCH In review KUROSAWA Takahiro 6 participants 32 messages Jan 19, 2006 – Feb 3, 2006

Subsystems (8)
lore
Share & tools
lore
#0 lore raw

cover Pzone based CKRM memory resource controller

(Changed the mail format into LKML-style and added linux-mm list to Cc:.
These patches are almost the same as what I sent to [email protected] this week.)

The pzone (pseudo zone) based memory resource controller is yet another implementation of the CKRM memory resource controller. The existing CKRM memory resource controller counts the number of pages that are allocated for tasks in a class in order to guarantee and limit memory resources. This requires changes to the existing code for page allocation and page reclaim.

This memory resource controller takes a different approach aiming at less impact to the existing Linux kernel code. The pzone is introduced to reserve the specified number of pages from the existing zone. The pzone uses the existing zone structure but adds several members. This enables us smaller impact to the memory management code; our memory resource controller doesn't require special LRU lists of pages or addition of a member to the page structure. Also, it doesn't require any changes for the algorithms in the memory management system.

Tasks in a class allocate pages using the zonelist that consists of pzones. The memory resource guarantee is achieved by preventing tasks in other classes from allocating pages from the pzones. The number of pages that a class holds can be achieved by limiting page allocations only from the pzones and disabling page allocations from conventional zones.

Thus, pages are accounted for the class of tasks that call __alloc_pages(). Resource guarantee and limit are handled as the same value. User-space daemons could be introduced in order to separate guarantee and limit.

The current implementation doesn't move resource account when the class of a task is changed. Moving resource account could be implemented by using Christoph Lameter's page migration patches.

The patches are against linux-2.6.15, the first patch is for introducing pzones and the second is for implementing memory resource controller using pzones. These patches are not adequately tested yet. They are still under development and need further work.

Regards,

KUROSAWA, Takahiro

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#1 lore raw

PATCH 1/2 Add the pzone

This patch implements the pzone (pseudo zone). A pzone can be used for reserving pages in a zone. Pzones are implemented by extending the zone structure and act almost the same as the conventional zones; we can specify pzones in a zonelist for __alloc_pages() and the vmscan code works on pzones with few modifications.

---
 include/linux/gfp.h    |    3 
 include/linux/mm.h     |   49 ++
 include/linux/mmzone.h |  118 ++++++
 include/linux/swap.h   |    2 
 mm/Kconfig             |    6 
 mm/page_alloc.c        |  845 +++++++++++++++++++++++++++++++++++++++++++++----
 mm/shmem.c             |    2 
 mm/vmscan.c            |   75 +++-
 8 files changed, 1020 insertions(+), 80 deletions(-)
include/linux/gfp.h +2 -1
diff -urNp a/include/linux/gfp.h b/include/linux/gfp.h
@@ -47,6 +47,7 @@ struct vm_area_struct;
 #define __GFP_ZERO	((__force gfp_t)0x8000u)/* Return zeroed page on success */
 #define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
 #define __GFP_HARDWALL   ((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */
+#define __GFP_NOLRU      ((__force gfp_t)0x40000u) /* GFP_USER but will not be in LRU lists */
 
 #define __GFP_BITS_SHIFT 20	/* Room for 20 __GFP_FOO bits */
 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
@@ -55,7 +56,7 @@ struct vm_area_struct;
 #define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \
 			__GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \
 			__GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \
-			__GFP_NOMEMALLOC|__GFP_HARDWALL)
+			__GFP_NOMEMALLOC|__GFP_HARDWALL|__GFP_NOLRU)
 
 #define GFP_ATOMIC	(__GFP_HIGH)
 #define GFP_NOIO	(__GFP_WAIT)
include/linux/mm.h +43 -6

97 lines not on this page · raw message

include/linux/mmzone.h +117 -1

159 lines not on this page · raw message

include/linux/swap.h +2 -0
diff -urNp a/include/linux/swap.h b/include/linux/swap.h
@@ -171,6 +171,8 @@ extern int rotate_reclaimable_page(struc
 extern void swap_setup(void);
 
 /* linux/mm/vmscan.c */
+extern int isolate_lru_pages(int, struct list_head *, struct list_head *,
+		int *);
 extern int try_to_free_pages(struct zone **, gfp_t);
 extern int zone_reclaim(struct zone *, gfp_t, unsigned int);
 extern int shrink_all_memory(int);
mm/Kconfig +6 -0
diff -urNp a/mm/Kconfig b/mm/Kconfig
@@ -132,3 +132,9 @@ config SPLIT_PTLOCK_CPUS
 	default "4096" if ARM && !CPU_CACHE_VIPT
 	default "4096" if PARISC && !PA20
 	default "4"
+
+config PSEUDO_ZONE
+	bool "Pseudo zone support"
+	help
+	  This option provides pseudo zone creation from a non-pseudo zone.
+	  Pseudo zones could be used for memory resource management.
mm/page_alloc.c +791 -54

994 lines not on this page · raw message

mm/shmem.c +1 -1
diff -urNp a/mm/shmem.c b/mm/shmem.c
@@ -366,7 +366,7 @@ static swp_entry_t *shmem_swp_alloc(stru
 		}
 
 		spin_unlock(&info->lock);
-		page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping) | __GFP_ZERO);
+		page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping) | __GFP_ZERO | __GFP_NOLRU);
 		if (page)
 			set_page_private(page, 0);
 		spin_lock(&info->lock);
mm/vmscan.c +58 -17

139 lines not on this page · raw message

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#2 lore raw

Re: [PATCH 1/2] Add the pzone

Quoted 7 lines · KUROSAWA Takahiro

This patch implements the pzone (pseudo zone). A pzone can be used for reserving pages in a zone. Pzones are implemented by extending the zone structure and act almost the same as the conventional zones; we can specify pzones in a zonelist for __alloc_pages() and the vmscan code works on pzones with few modifications.

[...]

include/linux/mm.h void put_page(struct page *page); · line 424

Quoted 7 lines
include/linux/mm.h +3 -2
-/* Page flags: | [SECTION] | [NODE] | ZONE | ... | FLAGS | */
-#define SECTIONS_PGOFF		((sizeof(unsigned long)*8) - SECTIONS_WIDTH)
+/* Page flags: | [PZONE] | [SECTION] | [NODE] | ZONE | ... | FLAGS | */
+#define PZONE_BIT_PGOFF		((sizeof(unsigned long)*8) - PZONE_BIT_WIDTH)
+#define SECTIONS_PGOFF		(PZONE_BIT_PGOFF - SECTIONS_WIDTH)
 #define NODES_PGOFF		(SECTIONS_PGOFF - NODES_WIDTH)
 #define ZONES_PGOFF		(NODES_PGOFF - ZONES_WIDTH)

In general this PZONE bit is really a part of the zone number. Much of the order of these bits is chosen to obtain the cheapest extraction of the most used bits, particularly the node/zone conbination or section number on the left. I would say put the PZONE_BIT next to ZONE probabally to the right of it? [See below for more reasons to put it there.]

Quoted 9 lines
include/linux/mm.h +1 -0
@@ -431,6 +438,7 @@ void put_page(struct page *page);
  * sections we define the shift as 0; that plus a 0 mask ensures
  * the compiler will optimise away reference to them.
  */
+#define PZONE_BIT_PGSHIFT	(PZONE_BIT_PGOFF * (PZONE_BIT_WIDTH != 0))
 #define SECTIONS_PGSHIFT	(SECTIONS_PGOFF * (SECTIONS_WIDTH != 0))
 #define NODES_PGSHIFT		(NODES_PGOFF * (NODES_WIDTH != 0))
 #define ZONES_PGSHIFT		(ZONES_PGOFF * (ZONES_WIDTH != 0))

include/linux/mm.h void put_page(struct page *page); · line 456

Quoted 8 lines
include/linux/mm.h +2 -2
@@ -443,10 +451,11 @@ void put_page(struct page *page);
 #endif
 #define ZONETABLE_PGSHIFT	ZONES_PGSHIFT
 
-#if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
-#error SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
+#if PZONE_BIT_WIDTH+SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
+#error PZONE_BIT_WIDTH+SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
 #endif

Do we have any bits left in the reserve on 32 bit machines? The reserve at last look was only 8 bits and there was little if any headroom in the rest of the flags word to extend it; if memory serves at least 22 of the 24 remaining bits was accounted for. Has this been tested on any such machines?

Quoted 4 lines
include/linux/mm.h +1 -0
+#define PZONE_BIT_MASK		((1UL << PZONE_BIT_WIDTH) - 1)
 #define ZONES_MASK		((1UL << ZONES_WIDTH) - 1)
 #define NODES_MASK		((1UL << NODES_WIDTH) - 1)
 #define SECTIONS_MASK		((1UL << SECTIONS_WIDTH) - 1)

[...]

Quoted 5 lines
include/linux/mm.h +5 -0
+#ifdef CONFIG_PSEUDO_ZONE
+static inline int page_in_pzone(struct page *page)
+{
+	return (page->flags >> PZONE_BIT_PGSHIFT) & PZONE_BIT_MASK;
+}

include/linux/mm.h void put_page(struct page *page); · line 486

Quoted 10 lines
include/linux/mm.h +10 -0
+
+static inline struct zone *page_zone(struct page *page)
+{
+	int idx;
+
+	idx = (page->flags >> ZONETABLE_PGSHIFT) & ZONETABLE_MASK;
+	if (page_in_pzone(page))
+		return pzone_table[idx].zone;
+	return zone_table[idx];
+}

Could we not do this all without changing the structure of the zone table at all by placing the PZONE_BIT either to the left or right of the ZONE in the flags. Then ZONETABLE_MASK could be extended to cover it when pzone's are enabled and the pzone's could be added to zone_table instead of their own pzone_table? This would mean the code above could be unmodified and much simpler.

Quoted 5 lines
include/linux/mm.h +5 -0
+
+static inline unsigned long page_to_nid(struct page *page)
+{
+	return page_zone(page)->zone_pgdat->node_id;
+}

[...]

include/linux/mmzone.h unsigned long __init node_memmap_size_by · line 351

Quoted 2 lines
include/linux/mmzone.h +2 -0
+#ifdef CONFIG_PSEUDO_ZONE
+#define MAX_NR_PZONES		1024

You seem to be allowing for 1024 pzone's here? But in pzone_setup_page_flags() you place the pzone_idx (an offset into the pzone_table) into the ZONE field of the page flags. This field is typically only two bits wide? I don't see this being increased in this patch, nor is there space for it generally to get much bigger not on 32 bit kernels anyhow (see comments about bits earlier)?

#define ZONES_SHIFT 2 /* ceil(log2(MAX_NR_ZONES)) */

Cheers.

-apw

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#3 lore raw

Re: [PATCH 1/2] Add the pzone

Quoted 6 lines · On Thu, 19 Jan 2006 18:04:43 +0000 Andy Whitcroft <[email protected]> wrote:
Quoted 6 lines
include/linux/mm.h +3 -2
-/* Page flags: | [SECTION] | [NODE] | ZONE | ... | FLAGS | */
-#define SECTIONS_PGOFF		((sizeof(unsigned long)*8) - SECTIONS_WIDTH)
+/* Page flags: | [PZONE] | [SECTION] | [NODE] | ZONE | ... | FLAGS | */
+#define PZONE_BIT_PGOFF		((sizeof(unsigned long)*8) - PZONE_BIT_WIDTH)
+#define SECTIONS_PGOFF		(PZONE_BIT_PGOFF - SECTIONS_WIDTH)
 #define NODES_PGOFF		(SECTIONS_PGOFF - NODES_WIDTH)
Quoted 8 lines
Quoted 1 line

#define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH)

In general this PZONE bit is really a part of the zone number. Much of the order of these bits is chosen to obtain the cheapest extraction of the most used bits, particularly the node/zone conbination or section number on the left. I would say put the PZONE_BIT next to ZONE probabally to the right of it? [See below for more reasons to put it there.]

Thanks for the comments. It looks much better to put PZONE_BIT to that place.

Quoted 12 lines
Quoted 12 lines
include/linux/mm.h +1 -0
@@ -431,6 +438,7 @@ void put_page(struct page *page);
  * sections we define the shift as 0; that plus a 0 mask ensures
  * the compiler will optimise away reference to them.
  */
+#define PZONE_BIT_PGSHIFT	(PZONE_BIT_PGOFF * (PZONE_BIT_WIDTH != 0))
 #define SECTIONS_PGSHIFT	(SECTIONS_PGOFF * (SECTIONS_WIDTH != 0))
 #define NODES_PGSHIFT		(NODES_PGOFF * (NODES_WIDTH != 0))
 #define ZONES_PGSHIFT		(ZONES_PGOFF * (ZONES_WIDTH != 0))
@@ -443,10 +451,11 @@ void put_page(struct page *page);
 #endif
 #define ZONETABLE_PGSHIFT	ZONES_PGSHIFT
 
Quoted 11 lines

include/linux/mm.h void put_page(struct page *page); · line 456

Quoted 5 lines
include/linux/mm.h +2 -2
-#if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
-#error SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
+#if PZONE_BIT_WIDTH+SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
+#error PZONE_BIT_WIDTH+SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
 #endif

Do we have any bits left in the reserve on 32 bit machines? The reserve at last look was only 8 bits and there was little if any headroom in the rest of the flags word to extend it; if memory serves at least 22 of the 24 remaining bits was accounted for. Has this been tested on any such machines?

At least it does compile and work on non-NUMA i386 configuration. But I haven't tested with CONFIG_NUMA or CONFIG_SPARSEMEM enabled.

Quoted 6 lines
Quoted 5 lines
include/linux/mm.h +5 -0
+
+static inline unsigned long page_to_nid(struct page *page)
+{
+	return page_zone(page)->zone_pgdat->node_id;
+}

[...]

Quoted 9 lines

include/linux/mmzone.h unsigned long __init node_memmap_size_by · line 351

Quoted 2 lines
include/linux/mmzone.h +2 -0
+#ifdef CONFIG_PSEUDO_ZONE
+#define MAX_NR_PZONES		1024

You seem to be allowing for 1024 pzone's here? But in pzone_setup_page_flags() you place the pzone_idx (an offset into the pzone_table) into the ZONE field of the page flags. This field is typically only two bits wide? I don't see this being increased in this patch, nor is there space for it generally to get much bigger not on 32 bit kernels anyhow (see comments about bits earlier)?

pzone_idx isn't placed on the ZONE field. The flags field of pzone pages is as follows:

Page flags: | [PZONE] | [pzone-idx] | ZONE | ... | FLAGS |

For pzones, the node number should be obtained from parent zone.

Thanks,

Signature · 7 lines
KUROSAWA, Takahiro

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#4 lore raw

Re: [PATCH 1/2] Add the pzone

Quoted 72 lines · KUROSAWA Takahiro
Quoted 6 lines · On Thu, 19 Jan 2006 18:04:43 +0000 Andy Whitcroft <[email protected]> wrote:
Quoted 6 lines
include/linux/mm.h +3 -2
-/* Page flags: | [SECTION] | [NODE] | ZONE | ... | FLAGS | */
-#define SECTIONS_PGOFF		((sizeof(unsigned long)*8) - SECTIONS_WIDTH)
+/* Page flags: | [PZONE] | [SECTION] | [NODE] | ZONE | ... | FLAGS | */
+#define PZONE_BIT_PGOFF		((sizeof(unsigned long)*8) - PZONE_BIT_WIDTH)
+#define SECTIONS_PGOFF		(PZONE_BIT_PGOFF - SECTIONS_WIDTH)

#define NODES_PGOFF (SECTIONS_PGOFF - NODES_WIDTH)

Quoted 8 lines
Quoted 1 line

#define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH)

In general this PZONE bit is really a part of the zone number. Much of the order of these bits is chosen to obtain the cheapest extraction of the most used bits, particularly the node/zone conbination or section number on the left. I would say put the PZONE_BIT next to ZONE probabally to the right of it? [See below for more reasons to put it there.]

Thanks for the comments. It looks much better to put PZONE_BIT to that place.

Quoted 12 lines
Quoted 12 lines
include/linux/mm.h +1 -0
@@ -431,6 +438,7 @@ void put_page(struct page *page);
 * sections we define the shift as 0; that plus a 0 mask ensures
 * the compiler will optimise away reference to them.
 */
+#define PZONE_BIT_PGSHIFT	(PZONE_BIT_PGOFF * (PZONE_BIT_WIDTH != 0))
 #define SECTIONS_PGSHIFT	(SECTIONS_PGOFF * (SECTIONS_WIDTH != 0))
 #define NODES_PGSHIFT		(NODES_PGOFF * (NODES_WIDTH != 0))
 #define ZONES_PGSHIFT		(ZONES_PGOFF * (ZONES_WIDTH != 0))
@@ -443,10 +451,11 @@ void put_page(struct page *page);
 #endif
 #define ZONETABLE_PGSHIFT	ZONES_PGSHIFT
 
Quoted 11 lines

include/linux/mm.h void put_page(struct page *page); · line 456

Quoted 5 lines
include/linux/mm.h +2 -2
-#if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
-#error SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
+#if PZONE_BIT_WIDTH+SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
+#error PZONE_BIT_WIDTH+SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
 #endif

Do we have any bits left in the reserve on 32 bit machines? The reserve at last look was only 8 bits and there was little if any headroom in the rest of the flags word to extend it; if memory serves at least 22 of the 24 remaining bits was accounted for. Has this been tested on any such machines?

At least it does compile and work on non-NUMA i386 configuration. But I haven't tested with CONFIG_NUMA or CONFIG_SPARSEMEM enabled.

Quoted 8 lines
Quoted 5 lines
include/linux/mm.h +5 -0
+
+static inline unsigned long page_to_nid(struct page *page)
+{
+	return page_zone(page)->zone_pgdat->node_id;
+}

[...]

Quoted 9 lines

include/linux/mmzone.h unsigned long __init node_memmap_size_by · line 351

Quoted 2 lines
include/linux/mmzone.h +2 -0
+#ifdef CONFIG_PSEUDO_ZONE
+#define MAX_NR_PZONES		1024

You seem to be allowing for 1024 pzone's here? But in pzone_setup_page_flags() you place the pzone_idx (an offset into the pzone_table) into the ZONE field of the page flags. This field is typically only two bits wide? I don't see this being increased in this patch, nor is there space for it generally to get much bigger not on 32 bit kernels anyhow (see comments about bits earlier)?

Quoted 6 lines

pzone_idx isn't placed on the ZONE field. The flags field of pzone pages is as follows:

Page flags: | [PZONE] | [pzone-idx] | ZONE | ... | FLAGS |

For pzones, the node number should be obtained from parent zone.

So you are in effect replacing the NODE element with the PZONE-IDX field. Firstly you haven't changed the format itself to do that. If it were sensible to do that (see below for other issues) I would suggest you simply extend the ZONE to encompas that entire area and use the higher zone 'numbers' to represent the pzone's.

Problems with this include:

1) the ZONE number for the standard zones are not unique in a NUMA system, we need the NUMA node number to make them unique. We assume we can locate the zone directly from the struct page, and currently that is done using the zonetable, using the (NODE,ZONE) tuple or the (SECTION,ZONE) tuple. Extending the ZONE over the NODE/SECTION element and eliminating those will prevent both NUMA and SPARSEMEM from working.

2) On 32 bit this space in total is FLAGS_RESERVED or a max of 9 bits (in -mm at least) on 32 bits architectures. You can't wedge three bits of ZONE, one bit of PZONE and 10 bits of pzone-idx into that space; it simply doesn't fit? Even if you just merge the pzone and zone together there isn't 10 bits available.

All in all it looks like this approach isn't going to work well for 32 bits machines with either NUMA or using SPARSEMEM.

-apw

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#5 lore raw

Re: [PATCH 1/2] Add the pzone

In reply to KUROSAWA Takahiro
Quoted 8 lines · KUROSAWA Takahiro

This patch implements the pzone (pseudo zone). A pzone can be used for reserving pages in a zone. Pzones are implemented by extending the zone structure and act almost the same as the conventional zones; we can specify pzones in a zonelist for __alloc_pages() and the vmscan code works on pzones with few modifications.

Quoted 10 lines
---
 include/linux/gfp.h    |    3 
 include/linux/mm.h     |   49 ++
 include/linux/mmzone.h |  118 ++++++
 include/linux/swap.h   |    2 
 mm/Kconfig             |    6 
 mm/page_alloc.c        |  845 +++++++++++++++++++++++++++++++++++++++++++++----
 mm/shmem.c             |    2 
 mm/vmscan.c            |   75 +++-
 8 files changed, 1020 insertions(+), 80 deletions(-)

Could you divide this *large* patch to several pieces ?

It looks you don't want to use functions based on zones, buddy-system, lru-list etc.. I think what you want is just a hierarchical memory allocator.
Why do you modify zone and make codes complicated ?
Can your memory allocater be implimented like mempool or hugetlb ?
They are not so invasive.

Bye,
-- Kame

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#6 lore raw

Re: [PATCH 1/2] Add the pzone

Quoted 10 lines · On Fri, 20 Jan 2006 16:08:28 +0900 KAMEZAWA Hiroyuki…
Quoted 9 lines
 include/linux/gfp.h    |    3 
 include/linux/mm.h     |   49 ++
 include/linux/mmzone.h |  118 ++++++
 include/linux/swap.h   |    2 
 mm/Kconfig             |    6 
 mm/page_alloc.c        |  845 +++++++++++++++++++++++++++++++++++++++++++++----
 mm/shmem.c             |    2 
 mm/vmscan.c            |   75 +++-
 8 files changed, 1020 insertions(+), 80 deletions(-)

Could you divide this *large* patch to several pieces ?

Ok, I'll split the patch.

Quoted 5 lines

It looks you don't want to use functions based on zones, buddy-system, lru-list etc.. I think what you want is just a hierarchical memory allocator.
Why do you modify zone and make codes complicated ?
Can your memory allocater be implimented like mempool or hugetlb ?
They are not so invasive.

mempool and hugetlb require their own shrinking code, don't they? I guess that we would need the routines like mm/vmscan.c if we are going to shrink user pages. Instead, I'd like to reuse the shrinking code in mm/vmscan.c.

Thanks,

Signature · 7 lines
KUROSAWA, Takahiro

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#7 lore raw

Re: [PATCH 1/2] Add the pzone

Quoted 11 lines · KUROSAWA Takahiro
Quoted 5 lines

It looks you don't want to use functions based on zones, buddy-system, lru-list etc.. I think what you want is just a hierarchical memory allocator.
Why do you modify zone and make codes complicated ?
Can your memory allocater be implimented like mempool or hugetlb ?
They are not so invasive.

mempool and hugetlb require their own shrinking code, don't they? I guess that we would need the routines like mm/vmscan.c if we are going to shrink user pages. Instead, I'd like to reuse the shrinking code in mm/vmscan.c.

I think you can reuse shrink_list() at least.
Code duplication you're afraid of can be small.
I think call shrink_list() from your own shrinking fuction will add good control on CKRM's memory region.

-- Kame

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#8 lore raw

PATCH 2/2 Add CKRM memory resource controller using pzones

In reply to KUROSAWA Takahiro

This patch implements the CKRM memory resource controller using pzones. This patch requires CKRM patched source code.

CKRM patches can be obtained from
http://sourceforge.net/project/showfiles.php?group_id=85838&package_id=163747

The CKRM patches requires configfs-patched source code:
http://oss.oracle.com/projects/ocfs2/dist/files/patches/2.6.15-rc5/2005-12-14/01_configfs.patch

---
 include/linux/gfp.h |   31 ++
 mm/Kconfig          |    8 
 mm/Makefile         |    2 
 mm/mem_rc_pzone.c   |  597 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 mm/mempolicy.c      |   10 
 5 files changed, 645 insertions(+), 3 deletions(-)
include/linux/gfp.h +31 -0
diff -urNp b/include/linux/gfp.h c/include/linux/gfp.h
@@ -104,12 +104,43 @@ static inline void arch_free_page(struct
 extern struct page *
 FASTCALL(__alloc_pages(gfp_t, unsigned int, struct zonelist *));
 
+#ifdef CONFIG_MEM_RC
+static inline int mem_rc_available(gfp_t gfp_mask, unsigned int order)
+{
+	gfp_mask &= GFP_LEVEL_MASK & ~__GFP_HIGHMEM;
+	return gfp_mask == GFP_USER && order == 0;
+}
+
+extern struct page *alloc_page_mem_rc(int nid, gfp_t gfp_mask);
+extern struct zonelist *mem_rc_get_zonelist(int nd, gfp_t gfp_mask,
+		unsigned int order);
+#else
+static inline int mem_rc_available(gfp_t gfp_mask, unsigned int order)
+{
+	return 0;
+}
+
+static inline struct page *alloc_page_mem_rc(int nid, gfp_t gfp_mask)
+{
+	return NULL;
+}
+
+static inline struct zonelist *mem_rc_get_zonelist(int nd, gfp_t gfp_mask,
+		unsigned int order)
+{
+	return NULL;
+}
+#endif
+
 static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
 						unsigned int order)
 {
 	if (unlikely(order >= MAX_ORDER))
 		return NULL;
 
+	if (mem_rc_available(gfp_mask, order))
+		return alloc_page_mem_rc(nid, gfp_mask);
+
 	return __alloc_pages(gfp_mask, order,
 		NODE_DATA(nid)->node_zonelists + gfp_zone(gfp_mask));
 }
mm/Kconfig +8 -0
diff -urNp b/mm/Kconfig c/mm/Kconfig
@@ -138,3 +138,11 @@ config PSEUDO_ZONE
 	help
 	  This option provides pseudo zone creation from a non-pseudo zone.
 	  Pseudo zones could be used for memory resource management.
+
+config MEM_RC
+	bool "Memory resource controller"
+	select PSEUDO_ZONE
+	depends on CPUMETER || CKRM
+	help
+	  This options will let you control the memory resource by using 
+	  the pseudo zone.
mm/Makefile +2 -0
diff -urNp b/mm/Makefile c/mm/Makefile
@@ -20,3 +20,5 @@ obj-$(CONFIG_SHMEM) += shmem.o
 obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
 obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
 obj-$(CONFIG_FS_XIP) += filemap_xip.o
+
+obj-$(CONFIG_MEM_RC) += mem_rc_pzone.o
mm/mem_rc_pzone.c +597 -0

597 lines not on this page · raw message

mm/mempolicy.c +7 -3
diff -urNp b/mm/mempolicy.c c/mm/mempolicy.c
@@ -726,8 +726,10 @@ get_vma_policy(struct task_struct *task,
 }
 
 /* Return a zonelist representing a mempolicy */
-static struct zonelist *zonelist_policy(gfp_t gfp, struct mempolicy *policy)
+static struct zonelist *zonelist_policy(gfp_t gfp, int order,
+		struct mempolicy *policy)
 {
+	struct zonelist *zl;
 	int nd;
 
 	switch (policy->policy) {
@@ -746,6 +748,8 @@ static struct zonelist *zonelist_policy(
 	case MPOL_INTERLEAVE: /* should not happen */
 	case MPOL_DEFAULT:
 		nd = numa_node_id();
+		if ((zl = mem_rc_get_zonelist(nd, gfp, order)) != NULL)
+			return zl;
 		break;
 	default:
 		nd = 0;
@@ -844,7 +848,7 @@ alloc_page_vma(gfp_t gfp, struct vm_area
 		}
 		return alloc_page_interleave(gfp, 0, nid);
 	}
-	return __alloc_pages(gfp, 0, zonelist_policy(gfp, pol));
+	return __alloc_pages(gfp, 0, zonelist_policy(gfp, 0, pol));
 }
 
 /**
@@ -876,7 +880,7 @@ struct page *alloc_pages_current(gfp_t g
 		pol = &default_policy;
 	if (pol->policy == MPOL_INTERLEAVE)
 		return alloc_page_interleave(gfp, order, interleave_nodes(pol));
-	return __alloc_pages(gfp, order, zonelist_policy(gfp, pol));
+	return __alloc_pages(gfp, order, zonelist_policy(gfp, order, pol));
 }
 EXPORT_SYMBOL(alloc_pages_current);
 

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#9 lore raw

cover Pzone based CKRM memory resource controller

In reply to KUROSAWA Takahiro

I've split the patches into smaller pieces in order to increase readability. The core part of the patchset is the fifth one with the subject "Add the pzone_create() function."

Changes since the last post:
* Fixed a bug that pages allocated with __GFP_COLD are incorrectly handled.
* Moved the PZONE bit in page flags next to the zone number bits in order to make changes by pzones smaller.
* Moved the nr_zones locking functions outside of the CONFIG_PSEUDO_ZONE because they are not directly related to pzones.

Thanks,

Signature · 7 lines
KUROSAWA, Takahiro

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#10 lore raw

PATCH 1/8 Add the __GFP_NOLRU flag

This patch adds the __GFP_NOLRU flag. This option should be used for GFP_USER/GFP_HIGHUSER page allocations that are not maintained in the zone LRU lists.

---
 include/linux/gfp.h |    3 ++-
 mm/shmem.c          |    2 +-
 2 files changed, 3 insertions(+), 2 deletions(-)
include/linux/gfp.h +2 -1
diff -urNp a/include/linux/gfp.h b/include/linux/gfp.h
@@ -47,6 +47,7 @@ struct vm_area_struct;
 #define __GFP_ZERO	((__force gfp_t)0x8000u)/* Return zeroed page on success */
 #define __GFP_NOMEMALLOC ((__force gfp_t)0x10000u) /* Don't use emergency reserves */
 #define __GFP_HARDWALL   ((__force gfp_t)0x20000u) /* Enforce hardwall cpuset memory allocs */
+#define __GFP_NOLRU      ((__force gfp_t)0x40000u) /* GFP_USER but will not be in LRU lists */
 
 #define __GFP_BITS_SHIFT 20	/* Room for 20 __GFP_FOO bits */
 #define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
@@ -55,7 +56,7 @@ struct vm_area_struct;
 #define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \
 			__GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \
 			__GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP| \
-			__GFP_NOMEMALLOC|__GFP_HARDWALL)
+			__GFP_NOMEMALLOC|__GFP_HARDWALL|__GFP_NOLRU)
 
 #define GFP_ATOMIC	(__GFP_HIGH)
 #define GFP_NOIO	(__GFP_WAIT)
mm/shmem.c +1 -1
diff -urNp a/mm/shmem.c b/mm/shmem.c
@@ -366,7 +366,7 @@ static swp_entry_t *shmem_swp_alloc(stru
 		}
 
 		spin_unlock(&info->lock);
-		page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping) | __GFP_ZERO);
+		page = shmem_dir_alloc(mapping_gfp_mask(inode->i_mapping) | __GFP_ZERO | __GFP_NOLRU);
 		if (page)
 			set_page_private(page, 0);
 		spin_lock(&info->lock);

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#11 lore raw

Re: [ckrm-tech] [PATCH 1/8] Add the __GFP_NOLRU flag

Quoted 3 lines · KUROSAWA Takahiro

This patch adds the __GFP_NOLRU flag. This option should be used for GFP_USER/GFP_HIGHUSER page allocations that are not maintained in the zone LRU lists.

Is this simply to mark pages which will never end up in the LRU? Why is this important?

-- Dave

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#12 lore raw

Re: [ckrm-tech] [PATCH 1/8] Add the __GFP_NOLRU flag

Hi,

Quoted 6 lines · On Tue, 31 Jan 2006 10:18:53 -0800 Dave Hansen <[email protected]> wrote:
Quoted 3 lines

This patch adds the __GFP_NOLRU flag. This option should be used for GFP_USER/GFP_HIGHUSER page allocations that are not maintained in the zone LRU lists.

Is this simply to mark pages which will never end up in the LRU? Why is this important?

The resource controller assumes that pages in pzones are linked to LRU lists or free lists in order to simplify the cleanup of pzones in classes. Cleaning up a pzone needs to know all the pages that belong to the pzone. So the resource controller is designed not to allocate pages from pzones that will never end up in the LRU.

Signature · 7 lines
KUROSAWA, Takahiro

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#13 lore raw

PATCH 2/8 Keep the number of zones while zone iterator loop

In reply to KUROSAWA Takahiro

This patch adds locking functions that are used for restricting addition and removal of zones while looking up zones by for_each_zone etc. This feature is required for pzones because zones are added and removed dynamically in pzones.

for_each_zone and its family should be surrounded by read_lock_nr_zones and read_unlock_nr_zones. The code that adds or removes zones should call write_lock_nr_zones and write_unlock_nr_zones.

---
 include/linux/mmzone.h |    4 ++
 mm/page_alloc.c        |   68 +++++++++++++++++++++++++++++++++++++++++++++++++
 mm/vmscan.c            |    2 +
 3 files changed, 74 insertions(+)
include/linux/mmzone.h +4 -0
diff -urNp linux-2.6.15/include/linux/mmzone.h a/include/linux/mmzone.h
@@ -322,6 +322,10 @@ void build_all_zonelists(void);
 void wakeup_kswapd(struct zone *zone, int order);
 int zone_watermark_ok(struct zone *z, int order, unsigned long mark,
 		int classzone_idx, int alloc_flags);
+void read_lock_nr_zones(void);
+void read_unlock_nr_zones(void);
+void write_lock_nr_zones(unsigned long *flagsp);
+void write_unlock_nr_zones(unsigned long *flagsp);
 
 #ifdef CONFIG_HAVE_MEMORY_PRESENT
 void memory_present(int nid, unsigned long start, unsigned long end);
mm/page_alloc.c +68 -0

181 lines not on this page · raw message

mm/vmscan.c +2 -0
diff -urNp linux-2.6.15/mm/vmscan.c a/mm/vmscan.c
@@ -1261,7 +1261,9 @@ static int kswapd(void *p)
 		}
 		finish_wait(&pgdat->kswapd_wait, &wait);
 
+		read_lock_nr_zones();
 		balance_pgdat(pgdat, 0, order);
+		read_unlock_nr_zones();
 	}
 	return 0;
 }

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#14 lore raw

PATCH 3/8 Add for_each_zone_in_node macro

In reply to KUROSAWA Takahiro

This patch adds for_each_zone_in_node macro. This macro iterates the block for each zone in the specific node.

---
 include/linux/mmzone.h |   15 +++++++++++++++
 mm/page_alloc.c        |    6 ++----
 mm/vmscan.c            |   20 ++++++--------------
 3 files changed, 23 insertions(+), 18 deletions(-)
include/linux/mmzone.h +15 -0
diff -urNp a/include/linux/mmzone.h b/include/linux/mmzone.h
@@ -375,6 +375,18 @@ static inline struct zone *next_zone(str
 	return zone;
 }
 
+static inline struct zone *next_zone_in_node(struct zone *zone, int len)
+{
+	pg_data_t *pgdat = zone->zone_pgdat;
+
+	if (zone < pgdat->node_zones + len - 1)
+		zone++;
+	else
+		zone = NULL;
+
+	return zone;
+}
+
 /**
  * for_each_zone - helper macro to iterate over all memory zones
  * @zone - pointer to struct zone variable
@@ -393,6 +405,9 @@ static inline struct zone *next_zone(str
 #define for_each_zone(zone) \
 	for (zone = pgdat_list->node_zones; zone; zone = next_zone(zone))
 
+#define for_each_zone_in_node(zone, pgdat, len) \
+	for (zone = pgdat->node_zones; zone; zone = next_zone_in_node(zone, len))
+
 static inline int is_highmem_idx(int idx)
 {
 	return (idx == ZONE_HIGHMEM);
mm/page_alloc.c +2 -4
diff -urNp a/mm/page_alloc.c b/mm/page_alloc.c
@@ -2124,12 +2124,11 @@ static int frag_show(struct seq_file *m,
 {
 	pg_data_t *pgdat = (pg_data_t *)arg;
 	struct zone *zone;
-	struct zone *node_zones = pgdat->node_zones;
 	unsigned long flags;
 	int order;
 
 	read_lock_nr_zones();
-	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) {
+	for_each_zone_in_node(zone, pgdat, MAX_NR_ZONES) {
 		if (!zone->present_pages)
 			continue;
 
@@ -2158,11 +2157,10 @@ static int zoneinfo_show(struct seq_file
 {
 	pg_data_t *pgdat = arg;
 	struct zone *zone;
-	struct zone *node_zones = pgdat->node_zones;
 	unsigned long flags;
 
 	read_lock_nr_zones();
-	for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; zone++) {
+	for_each_zone_in_node(zone, pgdat, MAX_NR_ZONES) {
 		int i;
 
 		if (!zone->present_pages)
mm/vmscan.c +6 -14
diff -urNp a/mm/vmscan.c b/mm/vmscan.c
@@ -1047,6 +1047,7 @@ static int balance_pgdat(pg_data_t *pgda
 	int priority;
 	int i;
 	int total_scanned, total_reclaimed;
+	struct zone *zone;
 	struct reclaim_state *reclaim_state = current->reclaim_state;
 	struct scan_control sc;
 
@@ -1060,11 +1061,8 @@ loop_again:
 
 	inc_page_state(pageoutrun);
 
-	for (i = 0; i < pgdat->nr_zones; i++) {
-		struct zone *zone = pgdat->node_zones + i;
-
+	for_each_zone_in_node(zone, pgdat, pgdat->nr_zones)
 		zone->temp_priority = DEF_PRIORITY;
-	}
 
 	for (priority = DEF_PRIORITY; priority >= 0; priority--) {
 		int end_zone = 0;	/* Inclusive.  0 = ZONE_DMA */
@@ -1102,11 +1100,8 @@ loop_again:
 			end_zone = pgdat->nr_zones - 1;
 		}
 scan:
-		for (i = 0; i <= end_zone; i++) {
-			struct zone *zone = pgdat->node_zones + i;
-
+		for_each_zone_in_node(zone, pgdat, end_zone)
 			lru_pages += zone->nr_active + zone->nr_inactive;
-		}
 
 		/*
 		 * Now scan the zone in the dma->highmem direction, stopping
@@ -1117,8 +1112,7 @@ scan:
 		 * pages behind kswapd's direction of progress, which would
 		 * cause too much scanning of the lower zones.
 		 */
-		for (i = 0; i <= end_zone; i++) {
-			struct zone *zone = pgdat->node_zones + i;
+		for_each_zone_in_node(zone, pgdat, end_zone) {
 			int nr_slab;
 
 			if (zone->present_pages == 0)
@@ -1183,11 +1177,9 @@ scan:
 			break;
 	}
 out:
-	for (i = 0; i < pgdat->nr_zones; i++) {
-		struct zone *zone = pgdat->node_zones + i;
-
+	for_each_zone_in_node(zone, pgdat, pgdat->nr_zones)
 		zone->prev_priority = zone->temp_priority;
-	}
+
 	if (!all_zones_ok) {
 		cond_resched();
 		goto loop_again;

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#15 lore raw

PATCH 4/8 Extract zone specific routines as functions

In reply to KUROSAWA Takahiro

This patch extract per-zone parts from __drain_pages() and __setup_per_zone_pages_min() as functions. The extracted functions will be used by pzone functions.

---
 page_alloc.c |  111 +++++++++++++++++++++++++++++++----------------------------
 1 file changed, 60 insertions(+), 51 deletions(-)
mm/page_alloc.c +60 -51
diff -urNp a/mm/page_alloc.c b/mm/page_alloc.c
@@ -588,28 +599,32 @@ void drain_remote_pages(void)
 }
 #endif
 
-#if defined(CONFIG_PM) || defined(CONFIG_HOTPLUG_CPU)
-static void __drain_pages(unsigned int cpu)
+#if defined(CONFIG_PM) || defined(CONFIG_HOTPLUG_CPU)
+static void __drain_zone_pages(struct zone *zone, int cpu)
 {
-	struct zone *zone;
+	struct per_cpu_pageset *pset;
 	int i;
 
-	read_lock_nr_zones();
-	for_each_zone(zone) {
-		struct per_cpu_pageset *pset;
-
-		pset = zone_pcp(zone, cpu);
-		for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
-			struct per_cpu_pages *pcp;
+	pset = zone_pcp(zone, cpu);
+	for (i = 0; i < ARRAY_SIZE(pset->pcp); i++) {
+		struct per_cpu_pages *pcp;
 
-			pcp = &pset->pcp[i];
-			pcp->count -= free_pages_bulk(zone, pcp->count,
-						&pcp->list, 0);
-		}
+		pcp = &pset->pcp[i];
+		pcp->count -= free_pages_bulk(zone, pcp->count,
+					&pcp->list, 0);
 	}
+}
+
+static void __drain_pages(unsigned int cpu)
+{
+	struct zone *zone;
+
+	read_lock_nr_zones();
+	for_each_zone(zone)
+		__drain_zone_pages(zone, cpu);
 	read_unlock_nr_zones();
 }
-#endif /* CONFIG_PM || CONFIG_HOTPLUG_CPU */
+#endif /* CONFIG_PM || CONFIG_HOTPLUG_CPU */
 
 #ifdef CONFIG_PM
 
@@ -2429,6 +2445,45 @@ static void setup_per_zone_lowmem_reserv
 	}
 }
 
+static void setup_zone_pages_min(struct zone *zone, unsigned long lowmem_pages)
+{
+	unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10);
+	unsigned long flags;
+	unsigned long tmp;
+
+	spin_lock_irqsave(&zone->lru_lock, flags);
+	tmp = (pages_min * zone->present_pages) / lowmem_pages;
+	if (is_highmem(zone)) {
+		/*
+		 * __GFP_HIGH and PF_MEMALLOC allocations usually don't
+		 * need highmem pages, so cap pages_min to a small
+		 * value here.
+		 *
+		 * The (pages_high-pages_low) and (pages_low-pages_min)
+		 * deltas controls asynch page reclaim, and so should
+		 * not be capped for highmem.
+		 */
+		int min_pages;
+
+		min_pages = zone->present_pages / 1024;
+		if (min_pages < SWAP_CLUSTER_MAX)
+			min_pages = SWAP_CLUSTER_MAX;
+		if (min_pages > 128)
+			min_pages = 128;
+		zone->pages_min = min_pages;
+	} else {
+		/*
+		 * If it's a lowmem zone, reserve a number of pages
+		 * proportionate to the zone's size.
+		 */
+		zone->pages_min = tmp;
+	}
+
+	zone->pages_low   = zone->pages_min + tmp / 4;
+	zone->pages_high  = zone->pages_min + tmp / 2;
+	spin_unlock_irqrestore(&zone->lru_lock, flags);
+}
+
 /*
  * setup_per_zone_pages_min - called when min_free_kbytes changes.  Ensures 
  *	that the pages_{min,low,high} values for each zone are set correctly 
@@ -2436,10 +2491,8 @@ static void setup_per_zone_lowmem_reserv
  */
 void setup_per_zone_pages_min(void)
 {
-	unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10);
 	unsigned long lowmem_pages = 0;
 	struct zone *zone;
-	unsigned long flags;
 
 	read_lock_nr_zones();
 	/* Calculate total number of !ZONE_HIGHMEM pages */
@@ -2448,40 +2501,8 @@ void setup_per_zone_pages_min(void)
 			lowmem_pages += zone->present_pages;
 	}
 
-	for_each_zone(zone) {
-		unsigned long tmp;
-		spin_lock_irqsave(&zone->lru_lock, flags);
-		tmp = (pages_min * zone->present_pages) / lowmem_pages;
-		if (is_highmem(zone)) {
-			/*
-			 * __GFP_HIGH and PF_MEMALLOC allocations usually don't
-			 * need highmem pages, so cap pages_min to a small
-			 * value here.
-			 *
-			 * The (pages_high-pages_low) and (pages_low-pages_min)
-			 * deltas controls asynch page reclaim, and so should
-			 * not be capped for highmem.
-			 */
-			int min_pages;
-
-			min_pages = zone->present_pages / 1024;
-			if (min_pages < SWAP_CLUSTER_MAX)
-				min_pages = SWAP_CLUSTER_MAX;
-			if (min_pages > 128)
-				min_pages = 128;
-			zone->pages_min = min_pages;
-		} else {
-			/*
-			 * If it's a lowmem zone, reserve a number of pages
-			 * proportionate to the zone's size.
-			 */
-			zone->pages_min = tmp;
-		}
-
-		zone->pages_low   = zone->pages_min + tmp / 4;
-		zone->pages_high  = zone->pages_min + tmp / 2;
-		spin_unlock_irqrestore(&zone->lru_lock, flags);
-	}
+	for_each_zone(zone)
+		setup_zone_pages_min(zone, lowmem_pages);
 	read_unlock_nr_zones();
 }
 

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#16 lore raw

PATCH 5/8 Add the pzone_create() function

In reply to KUROSAWA Takahiro

This patch implements creation of pzones. A pzone can be used for reserving pages in a conventional zone. Pzones are implemented by extending the zone structure and act almost the same as the conventional zones; we can specify pzones in a zonelist for __alloc_pages() and the vmscan code works on pzones with few modifications.

---
 include/linux/mm.h     |   49 ++++++++-
 include/linux/mmzone.h |   97 +++++++++++++++++
 mm/Kconfig             |    6 +
 mm/page_alloc.c        |  266 ++++++++++++++++++++++++++++++++++++++++++++++++-
 mm/vmscan.c            |   20 +++
 5 files changed, 430 insertions(+), 8 deletions(-)
include/linux/mm.h +45 -4
diff -urNp a/include/linux/mm.h b/include/linux/mm.h
@@ -397,6 +397,12 @@ void put_page(struct page *page);
  * with space for node: | SECTION | NODE | ZONE | ... | FLAGS |
  *   no space for node: | SECTION |     ZONE    | ... | FLAGS |
  */
+
+#ifdef CONFIG_PSEUDO_ZONE
+#define PZONE_BIT_WIDTH		1
+#else
+#define PZONE_BIT_WIDTH		0
+#endif
 #ifdef CONFIG_SPARSEMEM
 #define SECTIONS_WIDTH		SECTIONS_SHIFT
 #else
@@ -405,16 +411,21 @@ void put_page(struct page *page);
 
 #define ZONES_WIDTH		ZONES_SHIFT
 
-#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT <= FLAGS_RESERVED
+#if PZONE_BIT_WIDTH+SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT <= FLAGS_RESERVED
 #define NODES_WIDTH		NODES_SHIFT
 #else
 #define NODES_WIDTH		0
 #endif
 
-/* Page flags: | [SECTION] | [NODE] | ZONE | ... | FLAGS | */
+/*
+ * Page flags: | [SECTION] | [NODE] | ZONE | [PZONE(0)] | ... | FLAGS |
+ * If PZONE bit is 1, page flags are as follows:
+ * Page flags: |       [PZONE index]       | [PZONE(1)] | ... | FLAGS |
+ */
 #define SECTIONS_PGOFF		((sizeof(unsigned long)*8) - SECTIONS_WIDTH)
 #define NODES_PGOFF		(SECTIONS_PGOFF - NODES_WIDTH)
 #define ZONES_PGOFF		(NODES_PGOFF - ZONES_WIDTH)
+#define PZONE_BIT_PGOFF		(ZONES_PGOFF - PZONE_BIT_WIDTH)
 
 /*
  * We are going to use the flags for the page to node mapping if its in
@@ -434,6 +445,7 @@ void put_page(struct page *page);
 #define SECTIONS_PGSHIFT	(SECTIONS_PGOFF * (SECTIONS_WIDTH != 0))
 #define NODES_PGSHIFT		(NODES_PGOFF * (NODES_WIDTH != 0))
 #define ZONES_PGSHIFT		(ZONES_PGOFF * (ZONES_WIDTH != 0))
+#define PZONE_BIT_PGSHIFT	(PZONE_BIT_PGOFF * (PZONE_BIT_WIDTH != 0))
 
 /* NODE:ZONE or SECTION:ZONE is used to lookup the zone from a page. */
 #if FLAGS_HAS_NODE
@@ -443,13 +455,14 @@ void put_page(struct page *page);
 #endif
 #define ZONETABLE_PGSHIFT	ZONES_PGSHIFT
 
-#if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
-#error SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > FLAGS_RESERVED
+#if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH+PZONE_BIT_WIDTH > FLAGS_RESERVED
+#error SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH+PZONE_BIT_WIDTH > FLAGS_RESERVED
 #endif
 
 #define ZONES_MASK		((1UL << ZONES_WIDTH) - 1)
 #define NODES_MASK		((1UL << NODES_WIDTH) - 1)
 #define SECTIONS_MASK		((1UL << SECTIONS_WIDTH) - 1)
+#define PZONE_BIT_MASK		((1UL << PZONE_BIT_WIDTH) - 1)
 #define ZONETABLE_MASK		((1UL << ZONETABLE_SHIFT) - 1)
 
 static inline unsigned long page_zonenum(struct page *page)
@@ -460,6 +473,32 @@ static inline unsigned long page_zonenum
 struct zone;
 extern struct zone *zone_table[];
 
+#ifdef CONFIG_PSEUDO_ZONE
+static inline int page_in_pzone(struct page *page)
+{
+	return (page->flags >> PZONE_BIT_PGSHIFT) & PZONE_BIT_MASK;
+}
+
+static inline struct zone *page_zone(struct page *page)
+{
+	int idx;
+
+	idx = (page->flags >> ZONETABLE_PGSHIFT) & ZONETABLE_MASK;
+	if (page_in_pzone(page))
+		return pzone_table[idx].zone;
+	return zone_table[idx];
+}
+
+static inline unsigned long page_to_nid(struct page *page)
+{
+	return page_zone(page)->zone_pgdat->node_id;
+}
+#else
+static inline int page_in_pzone(struct page *page)
+{
+	return 0;
+}
+
 static inline struct zone *page_zone(struct page *page)
 {
 	return zone_table[(page->flags >> ZONETABLE_PGSHIFT) &
@@ -473,6 +512,8 @@ static inline unsigned long page_to_nid(
 	else
 		return page_zone(page)->zone_pgdat->node_id;
 }
+#endif
+
 static inline unsigned long page_to_section(struct page *page)
 {
 	return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
include/linux/mmzone.h +96 -1

132 lines not on this page · raw message

mm/Kconfig +6 -0
diff -urNp a/mm/Kconfig b/mm/Kconfig
@@ -132,3 +132,9 @@ config SPLIT_PTLOCK_CPUS
 	default "4096" if ARM && !CPU_CACHE_VIPT
 	default "4096" if PARISC && !PA20
 	default "4"
+
+config PSEUDO_ZONE
+	bool "Pseudo zone support"
+	help
+	  This option provides pseudo zone creation from a non-pseudo zone.
+	  Pseudo zones could be used for memory resource management.
mm/page_alloc.c +264 -2

305 lines not on this page · raw message

mm/vmscan.c +19 -1
diff -urNp a/mm/vmscan.c b/mm/vmscan.c
@@ -1080,7 +1080,24 @@ loop_again:
 			 * zone which needs scanning
 			 */
 			for (i = pgdat->nr_zones - 1; i >= 0; i--) {
-				struct zone *zone = pgdat->node_zones + i;
+#ifdef CONFIG_PSEUDO_ZONE
+				for (zone = pgdat->node_zones + i; zone;
+				     zone = pzone_next_in_zone(zone)) {
+					if (zone->present_pages == 0)
+						continue;
+
+					if (zone->all_unreclaimable &&
+							priority != DEF_PRIORITY)
+						continue;
+
+					if (!zone_watermark_ok(zone, order,
+						zone->pages_high, 0, 0)) {
+						end_zone = i;
+						goto scan;
+					}
+				}
+#else /* !CONFIG_PSEUDO_ZONE */
+				zone = pgdat->node_zones + i;
 
 				if (zone->present_pages == 0)
 					continue;
@@ -1094,6 +1111,7 @@ loop_again:
 					end_zone = i;
 					goto scan;
 				}
+#endif /* !CONFIG_PSEUDO_ZONE */
 			}
 			goto out;
 		} else {

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#17 lore raw

PATCH 6/8 Add the pzone_destroy() function

In reply to KUROSAWA Takahiro

This patch implements destruction of pzones. Pages in the destroyed pzones return into the parent zone (the zone from that the pzone was created).

---
 include/linux/mmzone.h |    1 
 include/linux/swap.h   |    2 
 mm/page_alloc.c        |  287 +++++++++++++++++++++++++++++++++++++++++++++++++
 mm/vmscan.c            |    4 
 4 files changed, 292 insertions(+), 2 deletions(-)
include/linux/mmzone.h +1 -0
diff -urNp a/include/linux/mmzone.h b/include/linux/mmzone.h
@@ -362,6 +362,7 @@ struct pzone_table {
 extern struct pzone_table pzone_table[];
 
 struct zone *pzone_create(struct zone *z, char *name, int npages);
+void pzone_destroy(struct zone *z);
 
 static inline void zone_init_pzone_link(struct zone *z)
 {
include/linux/swap.h +2 -0
diff -urNp a/include/linux/swap.h b/include/linux/swap.h
@@ -171,6 +171,8 @@ extern int rotate_reclaimable_page(struc
 extern void swap_setup(void);
 
 /* linux/mm/vmscan.c */
+extern int isolate_lru_pages(int, struct list_head *, struct list_head *,
+		int *);
 extern int try_to_free_pages(struct zone **, gfp_t);
 extern int zone_reclaim(struct zone *, gfp_t, unsigned int);
 extern int shrink_all_memory(int);
mm/page_alloc.c +287 -0

321 lines not on this page · raw message

mm/vmscan.c +2 -2
diff -urNp a/mm/vmscan.c b/mm/vmscan.c
@@ -591,8 +591,8 @@ keep:
  *
  * returns how many pages were moved onto *@dst.
  */
-static int isolate_lru_pages(int nr_to_scan, struct list_head *src,
-			     struct list_head *dst, int *scanned)
+int isolate_lru_pages(int nr_to_scan, struct list_head *src,
+		      struct list_head *dst, int *scanned)
 {
 	int nr_taken = 0;
 	struct page *page;

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#18 lore raw

PATCH 7/8 Make the number of pages in pzones resizable

In reply to KUROSAWA Takahiro

This patch makes the number of pages in the pzones resizable by adding the pzone_set_numpages() function.

---
 include/linux/mmzone.h |    1 
 mm/page_alloc.c        |  111 +++++++++++++++++++++++++++++++++++++++++++++++++
 mm/vmscan.c            |   29 ++++++++++++
 3 files changed, 141 insertions(+)
include/linux/mmzone.h +1 -0
diff -urNp a/include/linux/mmzone.h b/include/linux/mmzone.h
@@ -363,6 +363,7 @@ extern struct pzone_table pzone_table[];
 
 struct zone *pzone_create(struct zone *z, char *name, int npages);
 void pzone_destroy(struct zone *z);
+int pzone_set_numpages(struct zone *z, int npages);
 
 static inline void zone_init_pzone_link(struct zone *z)
 {
mm/page_alloc.c +111 -0

117 lines not on this page · raw message

mm/vmscan.c +29 -0
diff -urNp a/mm/vmscan.c b/mm/vmscan.c
@@ -1328,6 +1328,35 @@ int shrink_all_memory(int nr_pages)
 }
 #endif
 
+#ifdef CONFIG_PSEUDO_ZONE
+int shrink_zone_memory(struct zone *zone, int nr_pages)
+{
+	struct scan_control sc;
+
+	sc.gfp_mask = GFP_KERNEL;
+	sc.may_writepage = 1;
+	sc.may_swap = 1;
+	sc.nr_mapped = read_page_state(nr_mapped);
+	sc.nr_scanned = 0;
+	sc.nr_reclaimed = 0;
+	sc.priority = 0;
+
+	if (nr_pages < SWAP_CLUSTER_MAX)
+		sc.swap_cluster_max = nr_pages;
+	else
+		sc.swap_cluster_max = SWAP_CLUSTER_MAX;
+
+	sc.nr_to_reclaim = sc.swap_cluster_max;
+	sc.nr_to_scan = sc.swap_cluster_max;
+	sc.nr_mapped = total_memory;	/* XXX  to make vmscan aggressive */
+	refill_inactive_zone(zone, &sc);
+	sc.nr_to_scan = sc.swap_cluster_max;
+	shrink_cache(zone, &sc);
+
+	return sc.nr_reclaimed;
+}
+#endif
+
 #ifdef CONFIG_HOTPLUG_CPU
 /* It's optimal to keep kswapds on the same CPUs as their memory, but
    not required for correctness.  So if the last cpu in a node goes

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#19 lore raw

PATCH 8/8 Add a CKRM memory resource controller using pzones

In reply to KUROSAWA Takahiro

This patch implements the CKRM memory resource controller using pzones. This patch requires CKRM patched source code.

CKRM patches can be obtained from
http://sourceforge.net/project/showfiles.php?group_id=85838&package_id=163747

The CKRM patches requires configfs-patched source code:
http://oss.oracle.com/projects/ocfs2/dist/files/patches/2.6.15-rc5/2005-12-14/0
1_configfs.patch

---
 include/linux/gfp.h |   31 ++
 mm/Kconfig          |    8 
 mm/Makefile         |    2 
 mm/mem_rc_pzone.c   |  632 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 mm/mempolicy.c      |   10 
 5 files changed, 680 insertions(+), 3 deletions(-)
include/linux/gfp.h +31 -0
diff -urNp b/include/linux/gfp.h c/include/linux/gfp.h
@@ -104,12 +104,43 @@ static inline void arch_free_page(struct
 extern struct page *
 FASTCALL(__alloc_pages(gfp_t, unsigned int, struct zonelist *));
 
+#ifdef CONFIG_MEM_RC
+static inline int mem_rc_available(gfp_t gfp_mask, unsigned int order)
+{
+	gfp_mask &= GFP_LEVEL_MASK & ~(__GFP_HIGHMEM | __GFP_COLD);
+	return gfp_mask == GFP_USER && order == 0;
+}
+
+extern struct page *alloc_page_mem_rc(int nid, gfp_t gfp_mask);
+extern struct zonelist *mem_rc_get_zonelist(int nd, gfp_t gfp_mask,
+		unsigned int order);
+#else
+static inline int mem_rc_available(gfp_t gfp_mask, unsigned int order)
+{
+	return 0;
+}
+
+static inline struct page *alloc_page_mem_rc(int nid, gfp_t gfp_mask)
+{
+	return NULL;
+}
+
+static inline struct zonelist *mem_rc_get_zonelist(int nd, gfp_t gfp_mask,
+		unsigned int order)
+{
+	return NULL;
+}
+#endif
+
 static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask,
 						unsigned int order)
 {
 	if (unlikely(order >= MAX_ORDER))
 		return NULL;
 
+	if (mem_rc_available(gfp_mask, order))
+		return alloc_page_mem_rc(nid, gfp_mask);
+
 	return __alloc_pages(gfp_mask, order,
 		NODE_DATA(nid)->node_zonelists + gfp_zone(gfp_mask));
 }
mm/Kconfig +8 -0
diff -urNp b/mm/Kconfig c/mm/Kconfig
@@ -138,3 +138,11 @@ config PSEUDO_ZONE
 	help
 	  This option provides pseudo zone creation from a non-pseudo zone.
 	  Pseudo zones could be used for memory resource management.
+
+config MEM_RC
+	bool "Memory resource controller"
+	select PSEUDO_ZONE
+	depends on CPUMETER || CKRM
+	help
+	  This option will let you control the memory resource by using
+	  the pseudo zone.
mm/Makefile +2 -0
diff -urNp b/mm/Makefile c/mm/Makefile
@@ -20,3 +20,5 @@ obj-$(CONFIG_SHMEM) += shmem.o
 obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
 obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o
 obj-$(CONFIG_FS_XIP) += filemap_xip.o
+
+obj-$(CONFIG_MEM_RC) += mem_rc_pzone.o
mm/mem_rc_pzone.c +632 -0

632 lines not on this page · raw message

mm/mempolicy.c +7 -3
diff -urNp b/mm/mempolicy.c c/mm/mempolicy.c
@@ -726,8 +726,10 @@ get_vma_policy(struct task_struct *task,
 }
 
 /* Return a zonelist representing a mempolicy */
-static struct zonelist *zonelist_policy(gfp_t gfp, struct mempolicy *policy)
+static struct zonelist *zonelist_policy(gfp_t gfp, int order,
+		struct mempolicy *policy)
 {
+	struct zonelist *zl;
 	int nd;
 
 	switch (policy->policy) {
@@ -746,6 +748,8 @@ static struct zonelist *zonelist_policy(
 	case MPOL_INTERLEAVE: /* should not happen */
 	case MPOL_DEFAULT:
 		nd = numa_node_id();
+		if ((zl = mem_rc_get_zonelist(nd, gfp, order)) != NULL)
+			return zl;
 		break;
 	default:
 		nd = 0;
@@ -844,7 +848,7 @@ alloc_page_vma(gfp_t gfp, struct vm_area
 		}
 		return alloc_page_interleave(gfp, 0, nid);
 	}
-	return __alloc_pages(gfp, 0, zonelist_policy(gfp, pol));
+	return __alloc_pages(gfp, 0, zonelist_policy(gfp, 0, pol));
 }
 
 /**
@@ -876,7 +880,7 @@ struct page *alloc_pages_current(gfp_t g
 		pol = &default_policy;
 	if (pol->policy == MPOL_INTERLEAVE)
 		return alloc_page_interleave(gfp, order, interleave_nodes(pol));
-	return __alloc_pages(gfp, order, zonelist_policy(gfp, pol));
+	return __alloc_pages(gfp, order, zonelist_policy(gfp, order, pol));
 }
 EXPORT_SYMBOL(alloc_pages_current);
 

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#20 lore raw
In reply to KUROSAWA Takahiro

Kurosawa,

I like the idea of multiple controllers for a resource. Users will have options to choose from. Thanks for doing it.

I have few questions:
- how are shared pages handled ?
- what is the plan to support "limit" ?
- can you provide more information in stats ?
- is it designed to work with cpumeter alone (i.e without ckrm) ?

comment/suggestion:
- IMO, moving pages from a class at time of reclassification would be the right thing to do. May be we have to add a pointer to Chris patch and make sure it works as we expect.
- instead of adding the pseudo zone related code to the core memory files, you can put them in a separate file.
- Documentation on how to configure and use it would be good.

regards,

chandra

Quoted 4 lines · KUROSAWA Takahiro

I've split the patches into smaller pieces in order to increase readability. The core part of the patchset is the fifth one with the subject "Add the pzone_create() function."

Quoted 9 lines

Changes since the last post:
* Fixed a bug that pages allocated with __GFP_COLD are incorrectly handled.
* Moved the PZONE bit in page flags next to the zone number bits in order to make changes by pzones smaller.
* Moved the nr_zones locking functions outside of the CONFIG_PSEUDO_ZONE because they are not directly related to pzones.

Thanks,

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#21 lore raw

Chandra,

Quoted 2 lines · On Tue, 31 Jan 2006 18:58:18 -0800 chandra seetharaman <[email protected]>…

I like the idea of multiple controllers for a resource. Users will have options to choose from. Thanks for doing it.

You are welcome. Thanks for the comments.

Quoted 2 lines

I have few questions:
- how are shared pages handled ?

Shared pages are accounted to the class that a task in it allocate the pages. This behavior is different from the memory resource controller in CKRM.

Quoted 1 line

- what is the plan to support "limit" ?

To be honest, I don't have any specific idea to support "limit" currently. Probably the userspace daemon that enlarge "guarantee" to the specified "limit" might support the "limit", because "guarantee" in the pzone based memory resource controller also works as "limit".

Quoted 1 line

- can you provide more information in stats ?

Ok, I'll do that.

Quoted 1 line

- is it designed to work with cpumeter alone (i.e without ckrm) ?

Maybe it works with cpumeter.

Quoted 7 lines

comment/suggestion:
- IMO, moving pages from a class at time of reclassification would be the right thing to do. May be we have to add a pointer to Chris patch and make sure it works as we expect.

- instead of adding the pseudo zone related code to the core memory files, you can put them in a separate file.

That's right. But I guess that several static functions in mm/page_alloc.c would need to be exported.

Quoted 1 line

- Documentation on how to configure and use it would be good.

I think so too. I'll write some documents.

Thanks,

Signature · 7 lines
KUROSAWA, Takahiro

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#22 lore raw

Hi Chandra,

Quoted 9 lines

You are welcome. Thanks for the comments.

Quoted 2 lines

I have few questions:
- how are shared pages handled ?

Shared pages are accounted to the class that a task in it allocate the pages. This behavior is different from the memory resource controller in CKRM.

Quoted 6 lines
Quoted 1 line

- what is the plan to support "limit" ?

To be honest, I don't have any specific idea to support "limit" currently. Probably the userspace daemon that enlarge "guarantee" to the specified "limit" might support the "limit", because "guarantee" in the pzone based memory resource controller also works as "limit".

I think that this should be placed outside of Kurosawa's controller. That would be a kernel thread between CKRM API and the controller, which collects statistics about pzones to change the size of them between "guarantee" and "limit". An userspace daemon would be also OK.

To separate balancing pzones code from VM will keep the code simple.

Quoted 16 lines
Quoted 1 line

- can you provide more information in stats ?

Ok, I'll do that.

Quoted 1 line

- is it designed to work with cpumeter alone (i.e without ckrm) ?

Maybe it works with cpumeter.

Quoted 7 lines

comment/suggestion:
- IMO, moving pages from a class at time of reclassification would be the right thing to do. May be we have to add a pointer to Chris patch and make sure it works as we expect.

- instead of adding the pseudo zone related code to the core memory files, you can put them in a separate file.

Quoted 6 lines

That's right. But I guess that several static functions in mm/page_alloc.c would need to be exported.

Quoted 1 line

- Documentation on how to configure and use it would be good.

I think so too. I'll write some documents.

Thanks,
Hirokazu Takahashi.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#23 lore raw
In reply to KUROSAWA Takahiro
Quoted 8 lines · KUROSAWA Takahiro

Chandra,

Quoted 2 lines · On Tue, 31 Jan 2006 18:58:18 -0800 chandra seetharaman <[email protected]>…

I like the idea of multiple controllers for a resource. Users will have options to choose from. Thanks for doing it.

Quoted 8 lines

You are welcome. Thanks for the comments.

Quoted 2 lines

I have few questions:
- how are shared pages handled ?

Shared pages are accounted to the class that a task in it allocate the pages. This behavior is different from the memory resource controller in CKRM.

all others get a free access ? It may not be a good option. SHared pages either have to be accounted separately or shared between the classes that use them.

current memrc also charges to the class that brings the page in. Valerie is in the process of making changes to make the shared pages belong to a separate class.

Quoted 7 lines
Quoted 2 lines

- what is the plan to support "limit" ?

To be honest, I don't have any specific idea to support "limit" currently. Probably the userspace daemon that enlarge "guarantee" to the specified "limit" might support the "limit", because "guarantee" in the pzone based memory resource controller also works as "limit".

I am not able to visualize how this will work.

In simple terms, sum of guarantees should _not_ exceed the amount of available memory but, sum of limits _can_ exceed the amount of available memory. As far as i understand your implementation, guarantee is translated to present_pages of the pseudo zone (and is subtracted from paren't present_pages). How can one set limit to be same as guarantee ?

Quoted 8 lines
Quoted 2 lines

- can you provide more information in stats ?

Ok, I'll do that.

Quoted 1 line

- is it designed to work with cpumeter alone (i.e without ckrm) ?

Maybe it works with cpumeter.

have you tested it without ckrm (i mean only with cpumeter)

Quoted 11 lines
Quoted 8 lines

comment/suggestion:
- IMO, moving pages from a class at time of reclassification would be the right thing to do. May be we have to add a pointer to Chris patch and make sure it works as we expect.

- instead of adding the pseudo zone related code to the core memory files, you can put them in a separate file.

That's right. But I guess that several static functions in mm/page_alloc.c would need to be exported.

it will be a lot cleaner.

Quoted 7 lines
Quoted 2 lines

- Documentation on how to configure and use it would be good.

I think so too. I'll write some documents.

Thanks,

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#24 lore raw
Quoted 7 lines · On Wed, 01 Feb 2006 17:26:00 -0800 chandra seetharaman <[email protected]>…
Quoted 6 lines
Quoted 1 line

- what is the plan to support "limit" ?

To be honest, I don't have any specific idea to support "limit" currently. Probably the userspace daemon that enlarge "guarantee" to the specified "limit" might support the "limit", because "guarantee" in the pzone based memory resource controller also works as "limit".

Quoted 7 lines

I am not able to visualize how this will work.

In simple terms, sum of guarantees should _not_ exceed the amount of available memory but, sum of limits _can_ exceed the amount of available memory. As far as i understand your implementation, guarantee is translated to present_pages of the pseudo zone (and is subtracted from paren't present_pages). How can one set limit to be same as guarantee ?

The number of pages in the pseudo zones can also be considered as limit because tasks in a class can't allocate beyond the number of the pages that are allocated to the pseudo zones.

Quoted 9 lines
Quoted 7 lines
Quoted 1 line

- can you provide more information in stats ?

Ok, I'll do that.

Quoted 1 line

- is it designed to work with cpumeter alone (i.e without ckrm) ?

Maybe it works with cpumeter.

have you tested it without ckrm (i mean only with cpumeter)

The patches I had sent don't include a harness to cpumeter, so we can't run with cpumeter. I suppose we need little work for modifying mm/mem_rc_pzone.c to work with cpumeter because the file was originally written for cpumeter.

Signature · 7 lines
KUROSAWA, Takahiro

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#25 lore raw
Quoted 18 lines · KUROSAWA Takahiro
Quoted 7 lines · On Wed, 01 Feb 2006 17:26:00 -0800 chandra seetharaman <[email protected]>…
Quoted 6 lines
Quoted 1 line

- what is the plan to support "limit" ?

To be honest, I don't have any specific idea to support "limit" currently. Probably the userspace daemon that enlarge "guarantee" to the specified "limit" might support the "limit", because "guarantee" in the pzone based memory resource controller also works as "limit".

Quoted 7 lines

I am not able to visualize how this will work.

In simple terms, sum of guarantees should _not_ exceed the amount of available memory but, sum of limits _can_ exceed the amount of available memory. As far as i understand your implementation, guarantee is translated to present_pages of the pseudo zone (and is subtracted from paren't present_pages). How can one set limit to be same as guarantee ?

Quoted 3 lines

The number of pages in the pseudo zones can also be considered as limit because tasks in a class can't allocate beyond the number of the pages that are allocated to the pseudo zones.

Yes. but, it is true only when limit and guarantee are the same.

Consider the following scenario:
A system with 1024MB of memory.

I want to create 6 classes:
- 4 of which has guarantee of 128MB and limit of 512MB
- 2 of which has guarantee of 256MB and limit of 768MB

We cannot do this with this memrc. Can you explain how a userspace program can help me do this.

thanks,

chandra

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#26 lore raw
Quoted 24 lines · On Thu, 02 Feb 2006 16:37:37 -0800 chandra seetharaman <[email protected]>…
Quoted 15 lines
Quoted 7 lines
Quoted 6 lines
Quoted 1 line

- what is the plan to support "limit" ?

To be honest, I don't have any specific idea to support "limit" currently. Probably the userspace daemon that enlarge "guarantee" to the specified "limit" might support the "limit", because "guarantee" in the pzone based memory resource controller also works as "limit".

Quoted 7 lines

I am not able to visualize how this will work.

In simple terms, sum of guarantees should _not_ exceed the amount of available memory but, sum of limits _can_ exceed the amount of available memory. As far as i understand your implementation, guarantee is translated to present_pages of the pseudo zone (and is subtracted from paren't present_pages). How can one set limit to be same as guarantee ?

Quoted 3 lines

The number of pages in the pseudo zones can also be considered as limit because tasks in a class can't allocate beyond the number of the pages that are allocated to the pseudo zones.

Yes. but, it is true only when limit and guarantee are the same.

Consider the following scenario:
A system with 1024MB of memory.

Quoted 6 lines

I want to create 6 classes:
- 4 of which has guarantee of 128MB and limit of 512MB
- 2 of which has guarantee of 256MB and limit of 768MB

We cannot do this with this memrc. Can you explain how a userspace program can help me do this.

Our memrc with a userspace program doesn't help this case. If you'd like to setup classes like this, you can select the memory resource controller in current CKRM.

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#27 lore raw
Quoted 31 lines · KUROSAWA Takahiro
Quoted 28 lines · On Thu, 02 Feb 2006 16:37:37 -0800 chandra seetharaman <[email protected]>…
Quoted 15 lines
Quoted 7 lines
Quoted 6 lines
Quoted 1 line

- what is the plan to support "limit" ?

To be honest, I don't have any specific idea to support "limit" currently. Probably the userspace daemon that enlarge "guarantee" to the specified "limit" might support the "limit", because "guarantee" in the pzone based memory resource controller also works as "limit".

Quoted 7 lines

I am not able to visualize how this will work.

In simple terms, sum of guarantees should _not_ exceed the amount of available memory but, sum of limits _can_ exceed the amount of available memory. As far as i understand your implementation, guarantee is translated to present_pages of the pseudo zone (and is subtracted from paren't present_pages). How can one set limit to be same as guarantee ?

Quoted 3 lines

The number of pages in the pseudo zones can also be considered as limit because tasks in a class can't allocate beyond the number of the pages that are allocated to the pseudo zones.

Yes. but, it is true only when limit and guarantee are the same.

Consider the following scenario:
A system with 1024MB of memory.

I want to create 6 classes:
- 4 of which has guarantee of 128MB and limit of 512MB
- 2 of which has guarantee of 256MB and limit of 768MB

Quoted 6 lines
Quoted 2 lines

We cannot do this with this memrc. Can you explain how a userspace program can help me do this.

Our memrc with a userspace program doesn't help this case. If you'd like to setup classes like this, you can select the memory resource controller in current CKRM.

That is how we intended guarantee and limit to work. What was your understanding, and what one can do through the userspace support ?

Quoted 1 line

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#28 lore raw
In reply to KUROSAWA Takahiro

Hi KUROSAWA,

I tried to use the controller but having some problems.

- Created class a,
- set guarantee to 50(with parent having 100, i expected class a to get 50% of memory in the system).
- moved my shell to class a.
- Issued a make in the kernel tree.
It consistently fails with
-----------
make: getcwd: : Cannot allocate memory
Makefile:313: /scripts/Kbuild.include: No such file or directory Makefile:532: /arch/i386/Makefile: No such file or directory Can't open perl script "/scripts/setlocalversion": No such file or directory
make: *** No rule to make target `/arch/i386/Makefile'. Stop.
-----------
Note that the compilation succeeds if I move my shell to the default class.

I got a oops too:
------------------------------
kernel BUG at mm/page_alloc.c:1074!
invalid operand: 0000 [#1]
SMP

Modules linked in:
CPU:    1
EIP:    0060:[<c013768d>]    Not tainted VLI
EFLAGS: 00010256   (2.6.15n)

EIP is at __free_pages+0x17/0x42
eax: 00000000 ebx: 00000000 ecx: c17f8b80 edx: c17f8b80
esi: f7c85578 edi: c1931e20 ebp: c1931a20 esp: d9799f98
ds: 007b es: 007b ss: 0068
Process make (pid: 12576, threadinfo=d9798000 task=f6324530)

Stack: c1931e20 c01637d1 ffc5c000 0000001b bfe6c930 bfe6c930 00001000
d9798000
       c01026fb bfe6c930 00001000 40143f0c bfe6c930 00001000 bfe6c098
000000b7
       0000007b c010007b 000000b7 ffffe410 00000073 00000286 bfe6c06c
0000007b
Call Trace:
 [<c01637d1>] sys_getcwd+0x17f/0x18a
 [<c01026fb>] sysenter_past_esp+0x54/0x79
Code: 4b 78 0e 8b 56 04 8b 44 9e 08 e8 da f8 ff ff eb ef 5b 5e c3 53 89

c1 89 d3 89 c2 8b 00 f6 c4 40 74 03 8b 51 0c 8b 42 04 40 75 08 <0f> 0b 32 04 45 72 30 c0 f0 83 41 04 ff 0f 98 c0 84 c0 74 15 85
-------------------------------------
Note: "if (put_page_testzero(page)) {" is line 1074 in my source tree

Also, I do not see a mem= line in the stats file for the default class.

chandra

Quoted 4 lines · KUROSAWA Takahiro

I've split the patches into smaller pieces in order to increase readability. The core part of the patchset is the fifth one with the subject "Add the pzone_create() function."

Quoted 9 lines

Changes since the last post:
* Fixed a bug that pages allocated with __GFP_COLD are incorrectly handled.
* Moved the PZONE bit in page flags next to the zone number bits in order to make changes by pzones smaller.
* Moved the nr_zones locking functions outside of the CONFIG_PSEUDO_ZONE because they are not directly related to pzones.

Thanks,

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>

#29 lore raw
Quoted 18 lines · On Tue, 31 Jan 2006 19:07:35 -0800 chandra seetharaman <[email protected]>…

I tried to use the controller but having some problems.

- Created class a,
- set guarantee to 50(with parent having 100, i expected class a to get 50% of memory in the system).
- moved my shell to class a.
- Issued a make in the kernel tree.
It consistently fails with
-----------
make: getcwd: : Cannot allocate memory
Makefile:313: /scripts/Kbuild.include: No such file or directory Makefile:532: /arch/i386/Makefile: No such file or directory Can't open perl script "/scripts/setlocalversion": No such file or directory
make: *** No rule to make target `/arch/i386/Makefile'. Stop.
-----------
Note that the compilation succeeds if I move my shell to the default class.

Hmm... That should be a bug in the pzones because the default class has the same number of pages as the class a.

Could you show me the output of "cat /proc/zoneinfo" after setting up the class a? The information would help me debugging.

Quoted 24 lines

I got a oops too:
------------------------------
kernel BUG at mm/page_alloc.c:1074!
invalid operand: 0000 [#1]
SMP

Modules linked in:
CPU:    1
EIP:    0060:[<c013768d>]    Not tainted VLI
EFLAGS: 00010256   (2.6.15n)

EIP is at __free_pages+0x17/0x42
eax: 00000000 ebx: 00000000 ecx: c17f8b80 edx: c17f8b80
esi: f7c85578 edi: c1931e20 ebp: c1931a20 esp: d9799f98
ds: 007b es: 007b ss: 0068
Process make (pid: 12576, threadinfo=d9798000 task=f6324530)

Stack: c1931e20 c01637d1 ffc5c000 0000001b bfe6c930 bfe6c930 00001000
d9798000
       c01026fb bfe6c930 00001000 40143f0c bfe6c930 00001000 bfe6c098
000000b7
       0000007b c010007b 000000b7 ffffe410 00000073 00000286 bfe6c06c
0000007b
Call Trace:
 [<c01637d1>] sys_getcwd+0x17f/0x18a
 [<c01026fb>] sysenter_past_esp+0x54/0x79
Code: 4b 78 0e 8b 56 04 8b 44 9e 08 e8 da f8 ff ff eb ef 5b 5e c3 53 89
Quoted 6 lines

c1 89 d3 89 c2 8b 00 f6 c4 40 74 03 8b 51 0c 8b 42 04 40 75 08 <0f> 0b 32 04 45 72 30 c0 f0 83 41 04 ff 0f 98 c0 84 c0 74 15 85
-------------------------------------
Note: "if (put_page_testzero(page)) {" is line 1074 in my source tree

Also, I do not see a mem= line in the stats file for the default class.

My source tree has the same line. I'll investigate the oops.

Thanks for the report,

Signature · 7 lines
KUROSAWA, Takahiro

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to [email protected].  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
#30 lore raw
In reply to chandra seetharaman
Quoted 18 lines · On Tue, 31 Jan 2006 19:07:35 -0800 chandra seetharaman <[email protected]>…

I tried to use the controller but having some problems.

- Created class a,
- set guarantee to 50(with parent having 100, i expected class a to get 50% of memory in the system).
- moved my shell to class a.
- Issued a make in the kernel tree.
It consistently fails with
-----------
make: getcwd: : Cannot allocate memory
Makefile:313: /scripts/Kbuild.include: No such file or directory Makefile:532: /arch/i386/Makefile: No such file or directory Can't open perl script "/scripts/setlocalversion": No such file or directory
make: *** No rule to make target `/arch/i386/Makefile'. Stop.
-----------
Note that the compilation succeeds if I move my shell to the default class.

I could reproduce this problem. Could you try the attached patch?

Quoted 1 line

I got a oops too:

I can't reproduce the oops so far. Does this oops also occur constantly?

Index: mm/mem_rc_pzone.c
===================================================================
RCS file: /cvsroot/ckrm/memrc-pzone/mm/mem_rc_pzone.c,v retrieving revision 1.9

mem_rc_pzone.c +38 -29
diff -u -p -r1.9 mem_rc_pzone.c
@@ -38,7 +38,7 @@ struct mem_rc {
 	unsigned long guarantee;
 	struct mem_rc_domain *rcd;
 	struct zone **zones[MAX_NUMNODES];
-	struct zonelist *zonelists[MAX_NUMNODES];
+	struct zonelist *zonelists[MAX_NUMNODES][GFP_ZONETYPES];
 };
 
 
@@ -109,7 +109,7 @@ static void *mem_rc_create(void *arg, st
 	struct zone *parent, *z, *z_ref;
 	pg_data_t *pgdat;
 	int node, allocn;
-	int i, j;
+	int i, j, k;
 
 	allocn = first_node(rcd->nodes);
 	mr = kmalloc_node(sizeof(*mr), GFP_KERNEL, allocn);
@@ -132,13 +132,16 @@ static void *mem_rc_create(void *arg, st
 		memset(mr->zones[node], 0,
 		       sizeof(*mr->zones[node]) * MAX_NR_ZONES);
 
-		mr->zonelists[node]
-			= kmalloc_node(sizeof(*mr->zonelists[node]),
-				       GFP_KERNEL, allocn);
-		if (!mr->zonelists[node])
-			goto failed;
+		for (i = 0; i < GFP_ZONETYPES; i++) {
+			mr->zonelists[node][i]
+				= kmalloc_node(sizeof(*mr->zonelists[node]),
+					       GFP_KERNEL, allocn);
+			if (!mr->zonelists[node][i])
+				goto failed;
 
-		memset(mr->zonelists[node], 0, sizeof(*mr->zonelists[node]));
+			memset(mr->zonelists[node][i], 0,
+			       sizeof(*mr->zonelists[node][i]));
+		}
 
 		for (i = 0; i < MAX_NR_ZONES; i++) {
 			parent = pgdat->node_zones + i;
@@ -153,21 +156,22 @@ static void *mem_rc_create(void *arg, st
 	}
 
 	for_each_node_mask(node, rcd->nodes) {
-		/* NORMAL zones and DMA zones also in HIGHMEM zonelist. */
-		zl_ref = NODE_DATA(node)->node_zonelists + __GFP_HIGHMEM;
-		zl = mr->zonelists[node];
-
-		for (j = i = 0; i < ARRAY_SIZE(zl_ref->zones); i++) {
-			z_ref = zl_ref->zones[i];
-			if (!z_ref)
-				break;
-
-			z = mr->zones[node][zone_idx(z_ref)];
-			if (!z)
-				continue;
-			zl->zones[j++] = z;
+		for (i = 0; i < GFP_ZONETYPES; i++) {
+			zl_ref = NODE_DATA(node)->node_zonelists + i;
+			zl = mr->zonelists[node][i];
+
+			for (j = k = 0; k < ARRAY_SIZE(zl_ref->zones); k++) {
+				z_ref = zl_ref->zones[k];
+				if (!z_ref)
+					break;
+
+				z = mr->zones[node][zone_idx(z_ref)];
+				if (!z)
+					continue;
+				zl->zones[j++] = z;
+			}
+			zl->zones[j] = NULL;
 		}
-		zl->zones[j] = NULL;
 	}
 	up(&rcd->sem);
 
@@ -175,8 +179,10 @@ static void *mem_rc_create(void *arg, st
 
 failed:
 	for_each_node_mask(node, rcd->nodes) {
-		if (mr->zonelists[node])
-			kfree(mr->zonelists[node]);
+		for (i = 0; i < GFP_ZONETYPES; i++) {
+			if (mr->zonelists[node][i])
+				kfree(mr->zonelists[node][i]);
+		}
 
 		if (!mr->zones[node])
 			continue;
@@ -204,8 +210,10 @@ static void mem_rc_destroy(void *p)
 
 	down(&rcd->sem);
 	for (node = 0; node < MAX_NUMNODES; node++) {
-		if (mr->zonelists[node])
-			kfree(mr->zonelists[node]);
+		for (i = 0; i < GFP_ZONETYPES; i++) {
+			if (mr->zonelists[node][i])
+				kfree(mr->zonelists[node][i]);
+		}
 			
 		if (!mr->zones[node])
 			continue;
@@ -341,14 +349,15 @@ EXPORT_SYMBOL(mem_rc_get);
 struct page *alloc_page_mem_rc(int nid, gfp_t gfpmask)
 {
 	struct mem_rc *mr;
+	gfp_t zoneidx = gfpmask & GFP_ZONEMASK;
 
 	mr = mem_rc_get(current);
 	if (!mr)
 		return __alloc_pages(gfpmask, 0,
 				     NODE_DATA(nid)->node_zonelists
-				     + (gfpmask & GFP_ZONEMASK));
+				     + zoneidx);
 
-	return __alloc_pages(gfpmask, 0, mr->zonelists[nid]);
+	return __alloc_pages(gfpmask, 0, mr->zonelists[nid][zoneidx]);
 }
 EXPORT_SYMBOL(alloc_page_mem_rc);
 
@@ -364,5 +373,5 @@ struct zonelist *mem_rc_get_zonelist(int
 	if (!mr)
 		return NULL;
 
-	return mr->zonelists[nd];
+	return mr->zonelists[nd][gfpmask & GFP_ZONEMASK];
 }
#31 lore raw
Quoted 22 lines · On Fri, 3 Feb 2006 10:33:58 +0900 KUROSAWA Takahiro <[email protected]>…
Quoted 18 lines · On Tue, 31 Jan 2006 19:07:35 -0800 chandra seetharaman <[email protected]>…

I tried to use the controller but having some problems.

- Created class a,
- set guarantee to 50(with parent having 100, i expected class a to get 50% of memory in the system).
- moved my shell to class a.
- Issued a make in the kernel tree.
It consistently fails with
-----------
make: getcwd: : Cannot allocate memory
Makefile:313: /scripts/Kbuild.include: No such file or directory Makefile:532: /arch/i386/Makefile: No such file or directory Can't open perl script "/scripts/setlocalversion": No such file or directory
make: *** No rule to make target `/arch/i386/Makefile'. Stop.
-----------
Note that the compilation succeeds if I move my shell to the default class.

Quoted 1 line

I could reproduce this problem. Could you try the attached patch?

I'm sorry, the patch attached to my previous mail has a severe bug. Could you try this patch instead?
Also, the code still doesn't work if you enable preemption because of a locking problem so far...

Index: mm/mem_rc_pzone.c
===================================================================
RCS file: /cvsroot/ckrm/memrc-pzone/mm/mem_rc_pzone.c,v retrieving revision 1.9

mem_rc_pzone.c +38 -29
diff -u -p -r1.9 mem_rc_pzone.c
@@ -38,7 +38,7 @@ struct mem_rc {
 	unsigned long guarantee;
 	struct mem_rc_domain *rcd;
 	struct zone **zones[MAX_NUMNODES];
-	struct zonelist *zonelists[MAX_NUMNODES];
+	struct zonelist *zonelists[MAX_NUMNODES][GFP_ZONETYPES];
 };
 
 
@@ -109,7 +109,7 @@ static void *mem_rc_create(void *arg, st
 	struct zone *parent, *z, *z_ref;
 	pg_data_t *pgdat;
 	int node, allocn;
-	int i, j;
+	int i, j, k;
 
 	allocn = first_node(rcd->nodes);
 	mr = kmalloc_node(sizeof(*mr), GFP_KERNEL, allocn);
@@ -132,13 +132,16 @@ static void *mem_rc_create(void *arg, st
 		memset(mr->zones[node], 0,
 		       sizeof(*mr->zones[node]) * MAX_NR_ZONES);
 
-		mr->zonelists[node]
-			= kmalloc_node(sizeof(*mr->zonelists[node]),
-				       GFP_KERNEL, allocn);
-		if (!mr->zonelists[node])
-			goto failed;
+		for (i = 0; i < GFP_ZONETYPES; i++) {
+			mr->zonelists[node][i]
+				= kmalloc_node(sizeof(*mr->zonelists[node][i]),
+					       GFP_KERNEL, allocn);
+			if (!mr->zonelists[node][i])
+				goto failed;
 
-		memset(mr->zonelists[node], 0, sizeof(*mr->zonelists[node]));
+			memset(mr->zonelists[node][i], 0,
+			       sizeof(*mr->zonelists[node][i]));
+		}
 
 		for (i = 0; i < MAX_NR_ZONES; i++) {
 			parent = pgdat->node_zones + i;
@@ -153,21 +156,22 @@ static void *mem_rc_create(void *arg, st
 	}
 
 	for_each_node_mask(node, rcd->nodes) {
-		/* NORMAL zones and DMA zones also in HIGHMEM zonelist. */
-		zl_ref = NODE_DATA(node)->node_zonelists + __GFP_HIGHMEM;
-		zl = mr->zonelists[node];
-
-		for (j = i = 0; i < ARRAY_SIZE(zl_ref->zones); i++) {
-			z_ref = zl_ref->zones[i];
-			if (!z_ref)
-				break;
-
-			z = mr->zones[node][zone_idx(z_ref)];
-			if (!z)
-				continue;
-			zl->zones[j++] = z;
+		for (i = 0; i < GFP_ZONETYPES; i++) {
+			zl_ref = NODE_DATA(node)->node_zonelists + i;
+			zl = mr->zonelists[node][i];
+
+			for (j = k = 0; k < ARRAY_SIZE(zl_ref->zones); k++) {
+				z_ref = zl_ref->zones[k];
+				if (!z_ref)
+					break;
+
+				z = mr->zones[z_ref->zone_pgdat->node_id][zone_idx(z_ref)];
+				if (!z)
+					continue;
+				zl->zones[j++] = z;
+			}
+			zl->zones[j] = NULL;
 		}
-		zl->zones[j] = NULL;
 	}
 	up(&rcd->sem);
 
@@ -175,8 +179,10 @@ static void *mem_rc_create(void *arg, st
 
 failed:
 	for_each_node_mask(node, rcd->nodes) {
-		if (mr->zonelists[node])
-			kfree(mr->zonelists[node]);
+		for (i = 0; i < GFP_ZONETYPES; i++) {
+			if (mr->zonelists[node][i])
+				kfree(mr->zonelists[node][i]);
+		}
 
 		if (!mr->zones[node])
 			continue;
@@ -204,8 +210,10 @@ static void mem_rc_destroy(void *p)
 
 	down(&rcd->sem);
 	for (node = 0; node < MAX_NUMNODES; node++) {
-		if (mr->zonelists[node])
-			kfree(mr->zonelists[node]);
+		for (i = 0; i < GFP_ZONETYPES; i++) {
+			if (mr->zonelists[node][i])
+				kfree(mr->zonelists[node][i]);
+		}
 			
 		if (!mr->zones[node])
 			continue;
@@ -341,14 +349,15 @@ EXPORT_SYMBOL(mem_rc_get);
 struct page *alloc_page_mem_rc(int nid, gfp_t gfpmask)
 {
 	struct mem_rc *mr;
+	gfp_t zoneidx = gfpmask & GFP_ZONEMASK;
 
 	mr = mem_rc_get(current);
 	if (!mr)
 		return __alloc_pages(gfpmask, 0,
 				     NODE_DATA(nid)->node_zonelists
-				     + (gfpmask & GFP_ZONEMASK));
+				     + zoneidx);
 
-	return __alloc_pages(gfpmask, 0, mr->zonelists[nid]);
+	return __alloc_pages(gfpmask, 0, mr->zonelists[nid][zoneidx]);
 }
 EXPORT_SYMBOL(alloc_page_mem_rc);
 
@@ -364,5 +373,5 @@ struct zonelist *mem_rc_get_zonelist(int
 	if (!mr)
 		return NULL;
 
-	return mr->zonelists[nd];
+	return mr->zonelists[nd][gfpmask & GFP_ZONEMASK];
 }