From: Christoph Lameter We can use the global ZVC counters to establish the exact size of the LRU and the free pages. This allows a more accurate determination of the dirty ratio. This patch will fix the broken ratio calculations if large amounts of memory are allocated to huge pags or other consumers that do not put the pages on to the LRU. However, we are unable to use the accurate base in the case of HIGHMEM and an allocation excluding HIGHMEM pages. In that case just fall back to the old scheme. Signed-off-by: Christoph Lameter Signed-off-by: Andrew Morton --- mm/page-writeback.c | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) diff -puN mm/page-writeback.c~get_dirty_limits-accurately-calculate-the-available-memory-that-can-be-dirtied mm/page-writeback.c --- a/mm/page-writeback.c~get_dirty_limits-accurately-calculate-the-available-memory-that-can-be-dirtied +++ a/mm/page-writeback.c @@ -119,6 +119,35 @@ static void background_writeout(unsigned * We make sure that the background writeout level is below the adjusted * clamping level. */ + +static unsigned long determine_available_memory(struct address_space *mapping) +{ + unsigned long x = global_page_state(NR_FREE_PAGES) + + global_page_state(NR_INACTIVE) + + global_page_state(NR_ACTIVE); +#ifdef CONFIG_HIGHMEM + /* + * If this mapping can only allocate from low memory, + * we exclude high memory from our count. + */ + if (mapping && !(mapping_gfp_mask(mapping) & __GFP_HIGHMEM)) { + int node; + + for_each_online_node(node) { + struct zone *z = + &NODE_DATA(node)->node_zones[ZONE_HIGHMEM]; + + x -= zone_page_state(z, NR_FREE_PAGES) + + zone_page_state(z, NR_INACTIVE) + + zone_page_state(z, NR_INACTIVE); + } + } + + +#endif + return x; +} + static void get_dirty_limits(long *pbackground, long *pdirty, struct address_space *mapping) @@ -128,19 +157,9 @@ get_dirty_limits(long *pbackground, long int unmapped_ratio; long background; long dirty; - unsigned long available_memory = vm_total_pages; + unsigned long available_memory = determine_available_memory(mapping); struct task_struct *tsk; -#ifdef CONFIG_HIGHMEM - /* - * If this mapping can only allocate from low memory, - * we exclude high memory from our count. - */ - if (mapping && !(mapping_gfp_mask(mapping) & __GFP_HIGHMEM)) - available_memory -= totalhigh_pages; -#endif - - unmapped_ratio = 100 - ((global_page_state(NR_FILE_MAPPED) + global_page_state(NR_ANON_PAGES)) * 100) / vm_total_pages; _