diff -rupN linux-2.6.10/include/linux/mm.h linux-2.6.10-new/include/linux/mm.h --- linux-2.6.10/include/linux/mm.h 2005-12-10 12:48:54.826878000 -0500 +++ linux-2.6.10-new/include/linux/mm.h 2005-12-10 12:52:49.141822000 -0500 @@ -719,8 +719,13 @@ int write_one_page(struct page *page, in #define VM_MAX_READAHEAD 128 /* kbytes */ #define VM_MIN_READAHEAD 16 /* kbytes (includes current page) */ +#ifdef CONFIG_READAHEAD_CONGFIX +int do_page_cache_readahead(int sync, struct address_space *mapping, struct file *filp, + unsigned long offset, unsigned long nr_to_read); +#else int do_page_cache_readahead(struct address_space *mapping, struct file *filp, unsigned long offset, unsigned long nr_to_read); +#endif int force_page_cache_readahead(struct address_space *mapping, struct file *filp, unsigned long offset, unsigned long nr_to_read); void page_cache_readahead(struct address_space *mapping, diff -rupN linux-2.6.10/init/Kconfig linux-2.6.10-new/init/Kconfig --- linux-2.6.10/init/Kconfig 2005-12-10 12:48:54.886875000 -0500 +++ linux-2.6.10-new/init/Kconfig 2005-12-10 12:52:49.191824000 -0500 @@ -315,6 +315,19 @@ config CC_OPTIMIZE_FOR_SIZE If unsure, say N. +##begin of modification + +config READAHEAD_CONGFIX + bool "Fix a performance bug on readahead device congestion" + default n + ---help--- + Only true read"ahead" is disabled on the event of device congestion. + In other words, the readahead invoked by page misses would go ahead despite + the device congestion. This fixes a performance bug that causes single page + I/O requests in the event of device congestion. + +##end of modification + config SHMEM default y bool "Use full shmem filesystem" if EMBEDDED && MMU diff -rupN linux-2.6.10/mm/filemap.c linux-2.6.10-new/mm/filemap.c --- linux-2.6.10/mm/filemap.c 2005-12-10 12:48:54.936874000 -0500 +++ linux-2.6.10-new/mm/filemap.c 2005-12-10 12:52:49.251824000 -0500 @@ -1204,7 +1204,15 @@ retry_find: if (pgoff > ra_pages / 2) start = pgoff - ra_pages / 2; +#ifdef CONFIG_READAHEAD_CONGFIX + /* + * This readahead operation contains some synchronously + * requested data by the application. + */ + do_page_cache_readahead(1, mapping, file, start, ra_pages); +#else do_page_cache_readahead(mapping, file, start, ra_pages); +#endif } page = find_get_page(mapping, pgoff); if (!page) diff -rupN linux-2.6.10/mm/readahead.c linux-2.6.10-new/mm/readahead.c --- linux-2.6.10/mm/readahead.c 2005-12-10 12:48:54.986875000 -0500 +++ linux-2.6.10-new/mm/readahead.c 2005-12-10 12:52:49.311819000 -0500 @@ -306,6 +306,23 @@ int force_page_cache_readahead(struct ad * force_page_cache_readahead() will ignore queue congestion and will block on * request queues. */ +#ifdef CONFIG_READAHEAD_CONGFIX +/* + * Under READAHEAD_CONGFIX, we take one additional parameter indicating + * whether this readahead includes any synchronously requested data. + * + * Also, this version returns -1 when the readahead is not even attempted. + */ +int do_page_cache_readahead(int sync, + struct address_space *mapping, struct file *filp, + unsigned long offset, unsigned long nr_to_read) +{ + if (sync || !bdi_read_congested(mapping->backing_dev_info)) + return __do_page_cache_readahead(mapping, filp, + offset, nr_to_read); + return -1; +} +#else /* begin of !CONFIG_READAHEAD_CONGFIX */ int do_page_cache_readahead(struct address_space *mapping, struct file *filp, unsigned long offset, unsigned long nr_to_read) { @@ -314,6 +331,7 @@ int do_page_cache_readahead(struct addre offset, nr_to_read); return 0; } +#endif /* end of !CONFIG_READAHEAD_CONGFIX */ /* * Check how effective readahead is being. If the amount of started IO is @@ -472,15 +490,33 @@ do_io: ra->size = ra->next_size; ra->ahead_start = 0; /* Invalidate these */ ra->ahead_size = 0; +#ifdef CONFIG_READAHEAD_CONGFIX + /* + * This readahead operation contains some synchronously + * requested data by the application. + */ + actual = do_page_cache_readahead(1, mapping, filp, offset, + ra->size); +#else actual = do_page_cache_readahead(mapping, filp, offset, ra->size); - if(!first_access) { +#endif + if (!first_access) { /* * do not adjust the readahead window size the first * time, the ahead window might get closed if all * the pages are already in the cache. */ +#ifdef CONFIG_READAHEAD_CONGFIX + if (actual!=-1) { + /* Try the readahead window size adjustment only if + * the readahead is attempted. + */ + check_ra_success(ra, ra->size, actual, orig_next_size); + } +#else check_ra_success(ra, ra->size, actual, orig_next_size); +#endif } } else { /* @@ -503,12 +539,35 @@ do_io: average = (ra->currnt_wnd_hit + ra->average + 1) / 2; if (average > max) { +#ifdef CONFIG_READAHEAD_CONGFIX + int tmp_start = ra->start + ra->size; + int tmp_size = ra->next_size; + /* + * This readahead operation does not contain any synchronously + * requested data by the application. + */ + actual = do_page_cache_readahead(0, mapping, filp, + tmp_start, tmp_size); + if (actual != -1) { + /* Set the readahead window only if the readahead + * is attempted. + */ + ra->ahead_start = tmp_start; + ra->ahead_size = tmp_size; + + /* Try the readahead window size adjustment only if + * the readahead is attempted. + */ + check_ra_success(ra, ra->ahead_size, actual, orig_next_size); + } +#else ra->ahead_start = ra->start + ra->size; ra->ahead_size = ra->next_size; actual = do_page_cache_readahead(mapping, filp, ra->ahead_start, ra->ahead_size); check_ra_success(ra, ra->ahead_size, actual, orig_next_size); +#endif } } }