Index: linux-2.6.13-sp/mm/swap_prefetch.c =================================================================== --- linux-2.6.13-sp.orig/mm/swap_prefetch.c 2005-10-04 21:42:15.000000000 +1000 +++ linux-2.6.13-sp/mm/swap_prefetch.c 2005-10-04 21:43:04.000000000 +1000 @@ -13,6 +13,8 @@ #include #include #include +#include +#include /* Time to delay prefetching if vm is busy or prefetching unsuccessful */ #define PREFETCH_DELAY (HZ * 5) @@ -20,13 +22,12 @@ #define PREFETCH_INTERVAL (HZ) struct swapped_root_t { - unsigned long busy; - spinlock_t lock; - struct list_head list; - struct radix_tree_root swap_tree; - rwlock_t *rwlock; - unsigned int count; - unsigned int maxcount; + unsigned long busy; /* vm busy */ + spinlock_t lock; /* protects all data */ + struct list_head list; /* MRU list of swapped pages */ + struct radix_tree_root swap_tree; /* Lookup tree of pages */ + unsigned int count; /* Number of entries */ + unsigned int maxcount; /* Maximum entries allowed */ kmem_cache_t *cache; }; @@ -39,7 +40,6 @@ static struct swapped_root_t swapped = { .busy = 0, .list = LIST_HEAD_INIT(swapped.list), .swap_tree = RADIX_TREE_INIT(GFP_ATOMIC), - .rwlock = &swapper_space.tree_lock, .count = 0, }; @@ -47,7 +47,9 @@ static struct timer_list prefetch_timer; static DECLARE_WAIT_QUEUE_HEAD(kprefetchd_wait); -static unsigned long mapped_limit; +static unsigned long mapped_limit; /* Max mapped we will prefetch to */ +static unsigned long last_free = 0; /* Last total free pages */ +static unsigned long temp_free = 0; /* * Create kmem cache for swapped entries @@ -55,15 +57,14 @@ static unsigned long mapped_limit; void __init prepare_prefetch(void) { long total_memory = nr_free_pagecache_pages(); - long se_size = sizeof(struct swapped_entry_t); - swapped.cache = kmem_cache_create("swapped_entry", se_size, - 0, 0, NULL, NULL); + swapped.cache = kmem_cache_create("swapped_entry", + sizeof(struct swapped_entry_t), 0, 0, NULL, NULL); if (unlikely(!swapped.cache)) panic("prepare_prefetch(): cannot create swapped_entry SLAB cache"); - /* Set max count of swapped entries to 5% ram */ - swapped.maxcount = (total_memory / 20) * (PAGE_SIZE / se_size); + /* Set max number of entries to size of physical ram */ + swapped.maxcount = total_memory; /* Set maximum amount of mapped pages to prefetch to 2/3 ram */ mapped_limit = total_memory / 3 * 2; @@ -221,13 +222,13 @@ static int trickle_swap_cache_async(swp_ struct page *page = NULL; int ret = 0; - /* Entry may already exist */ - if (unlikely(!read_trylock(swapped.rwlock))) { + if (unlikely(!read_trylock(&swapper_space.tree_lock))) { ret = -1; goto out; } + /* Entry may already exist */ page = radix_tree_lookup(&swapper_space.page_tree, entry.val); - read_unlock(swapped.rwlock); + read_unlock(&swapper_space.tree_lock); if (page) { remove_from_swapped_list(entry.val); goto out; @@ -246,7 +247,6 @@ static int trickle_swap_cache_async(swp_ goto out; } - lru_cache_add(page); if (unlikely(swap_readpage(NULL, page))) { ret = -1; goto out; @@ -270,17 +270,35 @@ static int prefetch_suitable(void) if (__test_and_clear_bit(0, &swapped.busy)) goto out; + temp_free = 0; /* * Have some hysteresis between where page reclaiming and prefetching * will occur to prevent ping-ponging between them. */ for_each_zone(z) { + unsigned long free; + if (z->present_pages == 0) continue; - if (z->pages_high * 3 > z->free_pages) + free = z->free_pages; + if (z->pages_high * 3 > free) goto out; + temp_free += free; } + /* + * We check to see that pages are not being allocated elsewhere + * at any significant rate implying any degree of memory pressure + * (eg during file reads) + */ + if (last_free) { + if (temp_free + SWAP_CLUSTER_MAX * 2 < last_free) { + last_free = temp_free; + goto out; + } + } else + last_free = temp_free; + get_page_state(&ps); /* We shouldn't prefetch when we are doing writeback */ @@ -348,6 +366,7 @@ static int trickle_swap(void) goto out; pages += got_page; } + last_free = temp_free; return 1; out_unlock: @@ -362,6 +381,8 @@ static int kprefetchd(void *data) daemonize("kprefetchd"); set_user_nice(current, 19); + /* Set ioprio to lowest if supported by i/o scheduler */ + sys_ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_CLASS_IDLE); for ( ; ; ) { int prefetched; @@ -372,9 +393,10 @@ static int kprefetchd(void *data) finish_wait(&kprefetchd_wait, &wait); /* If trickle_swap() returns -1 the timer is not reset */ - if (!(prefetched = trickle_swap())) + if (!(prefetched = trickle_swap())) { + last_free = 0; delay_prefetch_timer(); - else if (prefetched == 1) + } else if (prefetched == 1) reset_prefetch_timer(); } return 0;