Hi Paul, > 2) Other block I/O output (eg dd if=/dev/zero of=/dev/sdi bs=4M) also > run very slowly What do you notice when running "top" and doing the above? Does the "buff" value grow high (+700MB), with high CPU usage? If so, I think this might be down to nr_free_buffer_pages(). This function includes the pages in all zones (including the HIGHMEM zone) in its calculations, while only DMA and NORMAL zone pages are used for buffers. This upsets the result from balance_dirty_state() (fs/buffer.c), and as a result the required flushing of buffers is only done as a result of running v low of pages in the DMA and NORMAL zones. I've attached a "quick hack" I did for 2.4.0. It doesn't completely solve the problem, but moves it in the right direction. Please let me know if this helps. Mark
diff -urN -X dontdiff linux-2.4.0/mm/page_alloc.c markhe-2.4.0/mm/page_alloc.c --- linux-2.4.0/mm/page_alloc.c Wed Jan 3 17:59:06 2001 +++ markhe-2.4.0/mm/page_alloc.c Mon Jan 15 15:35:14 2001 @@ -583,6 +583,27 @@ } /* + * Free pages in zone "type", and the zones below it. + */ +unsigned int nr_free_pages_zone (int type) +{ + unsigned int sum; + zone_t *zone; + pg_data_t *pgdat = pgdat_list; + + if (type >= MAX_NR_ZONES) + BUG(); + + sum = 0; + while (pgdat) { + for (zone = pgdat->node_zones; zone < pgdat->node_zones + type; +zone++) + sum += zone->free_pages; + pgdat = pgdat->node_next; + } + return sum; +} + +/* * Total amount of inactive_clean (allocatable) RAM: */ unsigned int nr_inactive_clean_pages (void) @@ -600,6 +621,25 @@ return sum; } +unsigned int nr_inactive_clean_pages_zone(int type) +{ + unsigned int sum; + zone_t *zone; + pg_data_t *pgdat = pgdat_list; + + if (type >= MAX_NR_ZONES) + BUG(); + type++; + + sum = 0; + while (pgdat) { + for (zone = pgdat->node_zones; zone < pgdat->node_zones + type; +zone++) + sum += zone->inactive_clean_pages; + pgdat = pgdat->node_next; + } + return sum; +} + /* * Amount of free RAM allocatable as buffer memory: */ @@ -607,9 +647,9 @@ { unsigned int sum; - sum = nr_free_pages(); - sum += nr_inactive_clean_pages(); - sum += nr_inactive_dirty_pages; + sum = nr_free_pages_zone(ZONE_NORMAL); + sum += nr_inactive_clean_pages_zone(ZONE_NORMAL); + sum += nr_inactive_dirty_pages; /* XXX */ /* * Keep our write behind queue filled, even if