From: Christoph Lameter Make ZONE_DMA optional in core code. - ifdef all code for ZONE_DMA and related definitions following the example for ZONE_DMA32 and ZONE_HIGHMEM. - Without ZONE_DMA, ZONE_HIGHMEM and ZONE_DMA32 we get to a ZONES_SHIFT of 0. - Modify the VM statistics to work correctly without a DMA zone. - Modify slab to not create DMA slabs if there is no ZONE_DMA. [apw@shadowen.org: Simplify calculation of the number of bits we need for ZONES_SHIFT] Signed-off-by: Christoph Lameter Cc: Andi Kleen Cc: "Luck, Tony" Cc: Kyle McMartin Cc: Matthew Wilcox Cc: James Bottomley Cc: Paul Mundt Signed-off-by: Andy Whitcroft Signed-off-by: Andrew Morton --- include/linux/gfp.h | 2 ++ include/linux/mmzone.h | 26 ++++++++++++++++++++++++-- include/linux/slab.h | 4 ++++ include/linux/vmstat.h | 17 +++++++++++++---- mm/page_alloc.c | 4 ++++ mm/slab.c | 5 ++++- mm/vmstat.c | 8 +++++++- 7 files changed, 58 insertions(+), 8 deletions(-) diff -puN include/linux/gfp.h~optional-zone_dma-in-the-vm include/linux/gfp.h --- a/include/linux/gfp.h~optional-zone_dma-in-the-vm +++ a/include/linux/gfp.h @@ -85,8 +85,10 @@ struct vm_area_struct; static inline enum zone_type gfp_zone(gfp_t flags) { +#ifdef CONFIG_ZONE_DMA if (flags & __GFP_DMA) return ZONE_DMA; +#endif #ifdef CONFIG_ZONE_DMA32 if (flags & __GFP_DMA32) return ZONE_DMA32; diff -puN include/linux/mmzone.h~optional-zone_dma-in-the-vm include/linux/mmzone.h --- a/include/linux/mmzone.h~optional-zone_dma-in-the-vm +++ a/include/linux/mmzone.h @@ -91,6 +91,7 @@ struct per_cpu_pageset { #endif enum zone_type { +#ifdef CONFIG_ZONE_DMA /* * ZONE_DMA is used when there are devices that are not able * to do DMA to all of addressable memory (ZONE_NORMAL). Then we @@ -111,6 +112,7 @@ enum zone_type { * <16M. */ ZONE_DMA, +#endif #ifdef CONFIG_ZONE_DMA32 /* * x86_64 needs two ZONE_DMAs because it supports devices that are @@ -147,11 +149,27 @@ enum zone_type { * match the requested limits. See gfp_zone() in include/linux/gfp.h */ -#if !defined(CONFIG_ZONE_DMA32) && !defined(CONFIG_HIGHMEM) +/* + * Count the active zones. Note that the use of defined(X) outside + * #if and family is not necessarily defined so ensure we cannot use + * it later. Use __ZONE_COUNT to work out how many shift bits we need. + */ +#define __ZONE_COUNT ( \ + defined(CONFIG_ZONE_DMA) \ + + defined(CONFIG_ZONE_DMA32) \ + + 1 \ + + defined(CONFIG_HIGHMEM) \ +) +#if __ZONE_COUNT < 2 +#define ZONES_SHIFT 0 +#elif __ZONE_COUNT <= 2 #define ZONES_SHIFT 1 -#else +#elif __ZONE_COUNT <= 4 #define ZONES_SHIFT 2 +#else +#error ZONES_SHIFT -- too many zones configured adjust calculation #endif +#undef __ZONE_COUNT struct zone { /* Fields commonly accessed by the page allocator */ @@ -448,7 +466,11 @@ static inline int is_dma32(struct zone * static inline int is_dma(struct zone *zone) { +#ifdef CONFIG_ZONE_DMA return zone == zone->zone_pgdat->node_zones + ZONE_DMA; +#else + return 0; +#endif } /* These two functions are used to setup the per zone pages min values */ diff -puN include/linux/slab.h~optional-zone_dma-in-the-vm include/linux/slab.h --- a/include/linux/slab.h~optional-zone_dma-in-the-vm +++ a/include/linux/slab.h @@ -72,7 +72,11 @@ extern const char *kmem_cache_name(kmem_ struct cache_sizes { size_t cs_size; kmem_cache_t *cs_cachep; +#ifdef CONFIG_ZONE_DMA kmem_cache_t *cs_dmacachep; +#else +#define cs_dmacachep cs_cachep +#endif }; extern struct cache_sizes malloc_sizes[]; diff -puN include/linux/vmstat.h~optional-zone_dma-in-the-vm include/linux/vmstat.h --- a/include/linux/vmstat.h~optional-zone_dma-in-the-vm +++ a/include/linux/vmstat.h @@ -17,6 +17,12 @@ * generated will simply be the increment of a global address. */ +#ifdef CONFIG_ZONE_DMA +#define DMA_ZONE(xx) xx##_DMA, +#else +#define DMA_ZONE(xx) +#endif + #ifdef CONFIG_ZONE_DMA32 #define DMA32_ZONE(xx) xx##_DMA32, #else @@ -29,7 +35,7 @@ #define HIGHMEM_ZONE(xx) #endif -#define FOR_ALL_ZONES(xx) xx##_DMA, DMA32_ZONE(xx) xx##_NORMAL HIGHMEM_ZONE(xx) +#define FOR_ALL_ZONES(xx) DMA_ZONE(xx) DMA32_ZONE(xx) xx##_NORMAL HIGHMEM_ZONE(xx) enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT, FOR_ALL_ZONES(PGALLOC), @@ -88,7 +94,8 @@ extern void vm_events_fold_cpu(int cpu); #endif /* CONFIG_VM_EVENT_COUNTERS */ #define __count_zone_vm_events(item, zone, delta) \ - __count_vm_events(item##_DMA + zone_idx(zone), delta) + __count_vm_events(item##_NORMAL - ZONE_NORMAL + \ + zone_idx(zone), delta) /* * Zone based page accounting with per cpu differentials. @@ -135,14 +142,16 @@ static inline unsigned long node_page_st struct zone *zones = NODE_DATA(node)->node_zones; return +#ifdef CONFIG_ZONE_DMA + zone_page_state(&zones[ZONE_DMA], item) + +#endif #ifdef CONFIG_ZONE_DMA32 zone_page_state(&zones[ZONE_DMA32], item) + #endif - zone_page_state(&zones[ZONE_NORMAL], item) + #ifdef CONFIG_HIGHMEM zone_page_state(&zones[ZONE_HIGHMEM], item) + #endif - zone_page_state(&zones[ZONE_DMA], item); + zone_page_state(&zones[ZONE_NORMAL], item); } extern void zone_statistics(struct zonelist *, struct zone *); diff -puN mm/page_alloc.c~optional-zone_dma-in-the-vm mm/page_alloc.c --- a/mm/page_alloc.c~optional-zone_dma-in-the-vm +++ a/mm/page_alloc.c @@ -72,7 +72,9 @@ static void __free_pages_ok(struct page * don't need any ZONE_NORMAL reservation */ int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1] = { +#ifdef CONFIG_ZONE_DMA 256, +#endif #ifdef CONFIG_ZONE_DMA32 256, #endif @@ -84,7 +86,9 @@ int sysctl_lowmem_reserve_ratio[MAX_NR_Z EXPORT_SYMBOL(totalram_pages); static char *zone_names[MAX_NR_ZONES] = { +#ifdef CONFIG_ZONE_DMA "DMA", +#endif #ifdef CONFIG_ZONE_DMA32 "DMA32", #endif diff -puN mm/slab.c~optional-zone_dma-in-the-vm mm/slab.c --- a/mm/slab.c~optional-zone_dma-in-the-vm +++ a/mm/slab.c @@ -1455,13 +1455,14 @@ void __init kmem_cache_init(void) ARCH_KMALLOC_FLAGS|SLAB_PANIC, NULL, NULL); } - +#ifdef CONFIG_ZONE_DMA sizes->cs_dmacachep = kmem_cache_create(names->name_dma, sizes->cs_size, ARCH_KMALLOC_MINALIGN, ARCH_KMALLOC_FLAGS|SLAB_CACHE_DMA| SLAB_PANIC, NULL, NULL); +#endif sizes++; names++; } @@ -2294,8 +2295,10 @@ kmem_cache_create (const char *name, siz cachep->slab_size = slab_size; cachep->flags = flags; cachep->gfpflags = 0; +#ifdef CONFIG_ZONE_DMA if (flags & SLAB_CACHE_DMA) cachep->gfpflags |= GFP_DMA; +#endif cachep->buffer_size = size; if (flags & CFLGS_OFF_SLAB) { diff -puN mm/vmstat.c~optional-zone_dma-in-the-vm mm/vmstat.c --- a/mm/vmstat.c~optional-zone_dma-in-the-vm +++ a/mm/vmstat.c @@ -437,6 +437,12 @@ struct seq_operations fragmentation_op = .show = frag_show, }; +#ifdef CONFIG_ZONE_DMA +#define TEXT_FOR_DMA(xx) xx "_dma", +#else +#define TEXT_FOR_DMA(xx) +#endif + #ifdef CONFIG_ZONE_DMA32 #define TEXT_FOR_DMA32(xx) xx "_dma32", #else @@ -449,7 +455,7 @@ struct seq_operations fragmentation_op = #define TEXT_FOR_HIGHMEM(xx) #endif -#define TEXTS_FOR_ZONES(xx) xx "_dma", TEXT_FOR_DMA32(xx) xx "_normal", \ +#define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \ TEXT_FOR_HIGHMEM(xx) static char *vmstat_text[] = { _