diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-17 22:05:47 +0000 |
commit | 27cfca1ec98e91261b1a5355d10a8996464b63af (patch) | |
tree | 8e895a53e372fa682b4c0a585b9377d67ed70d0e /mm/page_alloc.c | |
parent | 6a76fb7214c477ccf6582bd79c5b4ccc4f9c41b1 (diff) |
Look Ma' what I found on my harddisk ...
o New faster syscalls for 2.1.x, too
o Upgrade to 2.1.89.
Don't try to run this. It's flaky as hell. But feel free to debug ...
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 128 |
1 files changed, 95 insertions, 33 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 07264f81e..ed748bbfb 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -19,6 +19,7 @@ #include <linux/swapctl.h> #include <linux/interrupt.h> #include <linux/init.h> +#include <linux/pagemap.h> #include <asm/dma.h> #include <asm/system.h> /* for cli()/sti() */ @@ -101,6 +102,46 @@ static inline void remove_mem_queue(struct page * entry) static spinlock_t page_alloc_lock; #endif +/* + * This routine is used by the kernel swap deamon to determine + * whether we have "enough" free pages. It is fairly arbitrary, + * but this had better return false if any reasonable "get_free_page()" + * allocation could currently fail.. + * + * Currently we approve of the following situations: + * - the highest memory order has two entries + * - the highest memory order has one free entry and: + * - the next-highest memory order has two free entries + * - the highest memory order has one free entry and: + * - the next-highest memory order has one free entry + * - the next-next-highest memory order has two free entries + * + * [previously, there had to be two entries of the highest memory + * order, but this lead to problems on large-memory machines.] + */ +int free_memory_available(void) +{ + int i, retval = 0; + unsigned long flags; + struct free_area_struct * list = NULL; + + spin_lock_irqsave(&page_alloc_lock, flags); + /* We fall through the loop if the list contains one + * item. -- thanks to Colin Plumb <colin@nyx.net> + */ + for (i = 1; i < 4; ++i) { + list = free_area + NR_MEM_LISTS - i; + if (list->next == memory_head(list)) + break; + if (list->next->next == memory_head(list)) + continue; + retval = 1; + break; + } + spin_unlock_irqrestore(&page_alloc_lock, flags); + return retval; +} + static inline void free_pages_ok(unsigned long map_nr, unsigned long order) { struct free_area_struct *area = free_area + order; @@ -133,9 +174,12 @@ static inline void free_pages_ok(unsigned long map_nr, unsigned long order) void __free_page(struct page *page) { if (!PageReserved(page) && atomic_dec_and_test(&page->count)) { - delete_from_swap_cache(page); + if (PageSwapCache(page)) + panic ("Freeing swap cache page"); free_pages_ok(page->map_nr, 0); } + if (PageSwapCache(page) && atomic_read(&page->count) == 1) + panic ("Releasing swap cache page"); } void free_pages(unsigned long addr, unsigned long order) @@ -147,10 +191,14 @@ void free_pages(unsigned long addr, unsigned long order) if (PageReserved(map)) return; if (atomic_dec_and_test(&map->count)) { - delete_from_swap_cache(map); + if (PageSwapCache(map)) + panic ("Freeing swap cache pages"); free_pages_ok(map_nr, order); return; } + if (PageSwapCache(map) && atomic_read(&map->count) == 1) + panic ("Releasing swap cache pages at %p", + __builtin_return_address(0)); } } @@ -161,11 +209,13 @@ void free_pages(unsigned long addr, unsigned long order) change_bit((index) >> (1+(order)), (area)->map) #define CAN_DMA(x) (PageDMA(x)) #define ADDRESS(x) (PAGE_OFFSET + ((x) << PAGE_SHIFT)) -#define RMQUEUE(order, dma) \ +#define RMQUEUE(order, maxorder, dma) \ do { struct free_area_struct * area = free_area+order; \ unsigned long new_order = order; \ - do { struct page *prev = memory_head(area), *ret; \ - while (memory_head(area) != (ret = prev->next)) { \ + do { struct page *prev = memory_head(area), *ret = prev->next; \ + while (memory_head(area) != ret) { \ + if (new_order >= maxorder && ret->next == prev) \ + break; \ if (!dma || CAN_DMA(ret)) { \ unsigned long map_nr = ret->map_nr; \ (prev->next = ret->next)->prev = prev; \ @@ -176,6 +226,7 @@ do { struct free_area_struct * area = free_area+order; \ return ADDRESS(map_nr); \ } \ prev = ret; \ + ret = ret->next; \ } \ new_order++; area++; \ } while (new_order < NR_MEM_LISTS); \ @@ -194,36 +245,40 @@ do { unsigned long size = 1 << high; \ map->age = PAGE_INITIAL_AGE; \ } while (0) -unsigned long __get_free_pages(int priority, unsigned long order, int dma) +unsigned long __get_free_pages(int gfp_mask, unsigned long order) { - unsigned long flags; - int reserved_pages; + unsigned long flags, maxorder; if (order >= NR_MEM_LISTS) - return 0; + goto nopage; - if (in_interrupt() && priority != GFP_ATOMIC) { + /* + * "maxorder" is the highest order number that we're allowed + * to empty in order to find a free page.. + */ + maxorder = order + NR_MEM_LISTS/3; + if (gfp_mask & __GFP_MED) + maxorder += NR_MEM_LISTS/3; + if ((gfp_mask & __GFP_HIGH) || maxorder > NR_MEM_LISTS) + maxorder = NR_MEM_LISTS; + + if (in_interrupt() && (gfp_mask & __GFP_WAIT)) { static int count = 0; if (++count < 5) { printk("gfp called nonatomically from interrupt %p\n", - return_address()); - priority = GFP_ATOMIC; + return_address()); + gfp_mask &= ~__GFP_WAIT; } } - reserved_pages = 5; - if (priority != GFP_NFS) - reserved_pages = min_free_pages; repeat: spin_lock_irqsave(&page_alloc_lock, flags); - if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) { - RMQUEUE(order, dma); - spin_unlock_irqrestore(&page_alloc_lock, flags); - return 0; - } + RMQUEUE(order, maxorder, (gfp_mask & GFP_DMA)); spin_unlock_irqrestore(&page_alloc_lock, flags); - if (priority != GFP_BUFFER && try_to_free_page(priority, dma, 1)) + if ((gfp_mask & __GFP_WAIT) && try_to_free_page(gfp_mask)) goto repeat; + +nopage: return 0; } @@ -315,31 +370,38 @@ __initfunc(unsigned long free_area_init(unsigned long start_mem, unsigned long e void swap_in(struct task_struct * tsk, struct vm_area_struct * vma, pte_t * page_table, unsigned long entry, int write_access) { - unsigned long page = __get_free_page(GFP_KERNEL); + unsigned long page; + struct page *page_map; + + page_map = read_swap_cache(entry); if (pte_val(*page_table) != entry) { - free_page(page); + if (page_map) + free_page_and_swap_cache(page_address(page_map)); return; } - if (!page) { + if (!page_map) { set_pte(page_table, BAD_PAGE); swap_free(entry); oom(tsk); return; } - read_swap_page(entry, (char *) page); - if (pte_val(*page_table) != entry) { - free_page(page); - return; - } + + page = page_address(page_map); vma->vm_mm->rss++; - tsk->maj_flt++; - if (!write_access && add_to_swap_cache(&mem_map[MAP_NR(page)], entry)) { - /* keep swap page allocated for the moment (swap cache) */ + tsk->min_flt++; + swap_free(entry); + + if (!write_access || is_page_shared(page_map)) { set_pte(page_table, mk_pte(page, vma->vm_page_prot)); return; } + + /* The page is unshared, and we want write access. In this + case, it is safe to tear down the swap cache and give the + page over entirely to this process. */ + + delete_from_swap_cache(page_map); set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)))); - swap_free(entry); return; } |