diff options
author | KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> | 2008-10-18 23:28:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-10-20 11:52:39 -0400 |
commit | 52d4b9ac0b985168009c2a57098324e67bae171f (patch) | |
tree | b3e3b854166930af893be90ea30a7ab0d65c59e7 /mm/page_alloc.c | |
parent | c05555b572921c464d064d9267f7f7bc06d424fa (diff) |
memcg: allocate all page_cgroup at boot
Allocate all page_cgroup at boot and remove page_cgroup poitner from
struct page. This patch adds an interface as
struct page_cgroup *lookup_page_cgroup(struct page*)
All FLATMEM/DISCONTIGMEM/SPARSEMEM and MEMORY_HOTPLUG is supported.
Remove page_cgroup pointer reduces the amount of memory by
- 4 bytes per PAGE_SIZE.
- 8 bytes per PAGE_SIZE
if memory controller is disabled. (even if configured.)
On usual 8GB x86-32 server, this saves 8MB of NORMAL_ZONE memory.
On my x86-64 server with 48GB of memory, this saves 96MB of memory.
I think this reduction makes sense.
By pre-allocation, kmalloc/kfree in charge/uncharge are removed.
This means
- we're not necessary to be afraid of kmalloc faiulre.
(this can happen because of gfp_mask type.)
- we can avoid calling kmalloc/kfree.
- we can avoid allocating tons of small objects which can be fragmented.
- we can know what amount of memory will be used for this extra-lru handling.
I added printk message as
"allocated %ld bytes of page_cgroup"
"please try cgroup_disable=memory option if you don't want"
maybe enough informative for users.
Signed-off-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Reviewed-by: Balbir Singh <balbir@linux.vnet.ibm.com>
Cc: Daisuke Nishimura <nishimura@mxp.nes.nec.co.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 12 |
1 files changed, 3 insertions, 9 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index f2fc44ec1d44..d0a240fbb8bf 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #include <linux/backing-dev.h> | 44 | #include <linux/backing-dev.h> |
45 | #include <linux/fault-inject.h> | 45 | #include <linux/fault-inject.h> |
46 | #include <linux/page-isolation.h> | 46 | #include <linux/page-isolation.h> |
47 | #include <linux/memcontrol.h> | 47 | #include <linux/page_cgroup.h> |
48 | #include <linux/debugobjects.h> | 48 | #include <linux/debugobjects.h> |
49 | 49 | ||
50 | #include <asm/tlbflush.h> | 50 | #include <asm/tlbflush.h> |
@@ -223,17 +223,12 @@ static inline int bad_range(struct zone *zone, struct page *page) | |||
223 | 223 | ||
224 | static void bad_page(struct page *page) | 224 | static void bad_page(struct page *page) |
225 | { | 225 | { |
226 | void *pc = page_get_page_cgroup(page); | ||
227 | |||
228 | printk(KERN_EMERG "Bad page state in process '%s'\n" KERN_EMERG | 226 | printk(KERN_EMERG "Bad page state in process '%s'\n" KERN_EMERG |
229 | "page:%p flags:0x%0*lx mapping:%p mapcount:%d count:%d\n", | 227 | "page:%p flags:0x%0*lx mapping:%p mapcount:%d count:%d\n", |
230 | current->comm, page, (int)(2*sizeof(unsigned long)), | 228 | current->comm, page, (int)(2*sizeof(unsigned long)), |
231 | (unsigned long)page->flags, page->mapping, | 229 | (unsigned long)page->flags, page->mapping, |
232 | page_mapcount(page), page_count(page)); | 230 | page_mapcount(page), page_count(page)); |
233 | if (pc) { | 231 | |
234 | printk(KERN_EMERG "cgroup:%p\n", pc); | ||
235 | page_reset_bad_cgroup(page); | ||
236 | } | ||
237 | printk(KERN_EMERG "Trying to fix it up, but a reboot is needed\n" | 232 | printk(KERN_EMERG "Trying to fix it up, but a reboot is needed\n" |
238 | KERN_EMERG "Backtrace:\n"); | 233 | KERN_EMERG "Backtrace:\n"); |
239 | dump_stack(); | 234 | dump_stack(); |
@@ -457,7 +452,6 @@ static inline int free_pages_check(struct page *page) | |||
457 | free_page_mlock(page); | 452 | free_page_mlock(page); |
458 | if (unlikely(page_mapcount(page) | | 453 | if (unlikely(page_mapcount(page) | |
459 | (page->mapping != NULL) | | 454 | (page->mapping != NULL) | |
460 | (page_get_page_cgroup(page) != NULL) | | ||
461 | (page_count(page) != 0) | | 455 | (page_count(page) != 0) | |
462 | (page->flags & PAGE_FLAGS_CHECK_AT_FREE))) | 456 | (page->flags & PAGE_FLAGS_CHECK_AT_FREE))) |
463 | bad_page(page); | 457 | bad_page(page); |
@@ -603,7 +597,6 @@ static int prep_new_page(struct page *page, int order, gfp_t gfp_flags) | |||
603 | { | 597 | { |
604 | if (unlikely(page_mapcount(page) | | 598 | if (unlikely(page_mapcount(page) | |
605 | (page->mapping != NULL) | | 599 | (page->mapping != NULL) | |
606 | (page_get_page_cgroup(page) != NULL) | | ||
607 | (page_count(page) != 0) | | 600 | (page_count(page) != 0) | |
608 | (page->flags & PAGE_FLAGS_CHECK_AT_PREP))) | 601 | (page->flags & PAGE_FLAGS_CHECK_AT_PREP))) |
609 | bad_page(page); | 602 | bad_page(page); |
@@ -3438,6 +3431,7 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat, | |||
3438 | pgdat->nr_zones = 0; | 3431 | pgdat->nr_zones = 0; |
3439 | init_waitqueue_head(&pgdat->kswapd_wait); | 3432 | init_waitqueue_head(&pgdat->kswapd_wait); |
3440 | pgdat->kswapd_max_order = 0; | 3433 | pgdat->kswapd_max_order = 0; |
3434 | pgdat_page_cgroup_init(pgdat); | ||
3441 | 3435 | ||
3442 | for (j = 0; j < MAX_NR_ZONES; j++) { | 3436 | for (j = 0; j < MAX_NR_ZONES; j++) { |
3443 | struct zone *zone = pgdat->node_zones + j; | 3437 | struct zone *zone = pgdat->node_zones + j; |