diff -urN 2.2.10-bigmem-D/arch/i386/mm/init.c 2.2.10-bigmem/arch/i386/mm/init.c --- 2.2.10-bigmem-D/arch/i386/mm/init.c Sat Aug 7 15:02:59 1999 +++ 2.2.10-bigmem/arch/i386/mm/init.c Sat Aug 7 19:41:37 1999 @@ -228,15 +228,25 @@ #ifdef CONFIG_BIGMEM unsigned long bigmem_start; unsigned long bigmem_end; +unsigned long bigmem_mapnr; int nr_free_bigmem = 0; +/* NOTE: fixmap_init alloc all the fixmap pagetables contigous on the + physical space so we can cache the place of the first one and move + around without checking the pgd every time. */ pte_t *kmap_pte; pgprot_t kmap_prot; -static void kmap_init(void) +#define kmap_get_fixmap_pte(vaddr) \ + pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) + +static void __init kmap_init(void) { - unsigned long kmap_vstart = __fix_to_virt(FIX_KMAP_START); + unsigned long kmap_vstart; + + /* cache the first kmap pte */ + kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); + kmap_pte = kmap_get_fixmap_pte(kmap_vstart); - kmap_pte = pte_offset(pmd_offset(pgd_offset_k(kmap_vstart), kmap_vstart), kmap_vstart); kmap_prot = PAGE_KERNEL; if (boot_cpu_data.x86_capability & X86_FEATURE_PGE) pgprot_val(kmap_prot) |= _PAGE_GLOBAL; @@ -431,11 +441,17 @@ unsigned long tmp; end_mem &= PAGE_MASK; +#ifdef CONFIG_BIGMEM + bigmem_start = PAGE_ALIGN(bigmem_start); + bigmem_end &= PAGE_MASK; +#endif high_memory = (void *) end_mem; #ifndef CONFIG_BIGMEM max_mapnr = num_physpages = MAP_NR(end_mem); #else max_mapnr = num_physpages = PHYSMAP_NR(bigmem_end); + /* cache the bigmem_mapnr */ + bigmem_mapnr = PHYSMAP_NR(bigmem_start); #endif /* clear the zero-page */ diff -urN 2.2.10-bigmem-D/include/asm-i386/fixmap.h 2.2.10-bigmem/include/asm-i386/fixmap.h --- 2.2.10-bigmem-D/include/asm-i386/fixmap.h Thu Aug 5 19:08:01 1999 +++ 2.2.10-bigmem/include/asm-i386/fixmap.h Sat Aug 7 20:02:24 1999 @@ -60,8 +60,8 @@ FIX_LI_PCIB, /* Lithium PCI Bridge B */ #endif #ifdef CONFIG_BIGMEM - FIX_KMAP_START, /* reserved pte's for temporary kernel mappings */ - FIX_KMAP_END = FIX_KMAP_START+(KM_TYPE_NR*NR_CPUS), + FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ + FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, #endif __end_of_fixed_addresses }; diff -urN 2.2.10-bigmem-D/include/asm-i386/kmap.h 2.2.10-bigmem/include/asm-i386/kmap.h --- 2.2.10-bigmem-D/include/asm-i386/kmap.h Thu Aug 5 19:08:02 1999 +++ 2.2.10-bigmem/include/asm-i386/kmap.h Sat Aug 7 20:02:25 1999 @@ -21,13 +21,15 @@ extern pte_t *kmap_pte; extern pgprot_t kmap_prot; +#define is_bigmem_address(kaddr) (__pa(kaddr) >= bigmem_start) + extern inline unsigned long kmap(unsigned long kaddr, enum km_type type) { - if (__pa(kaddr) < bigmem_start) + if (!is_bigmem_address(kaddr)) return kaddr; { enum fixed_addresses idx = type+KM_TYPE_NR*smp_processor_id(); - unsigned long vaddr = __fix_to_virt(FIX_KMAP_START+idx); + unsigned long vaddr = __fix_to_virt(FIX_KMAP_BEGIN+idx); #ifdef KMAP_DEBUG if (!pte_none(*(kmap_pte-idx))) @@ -49,7 +51,7 @@ { #ifdef KMAP_DEBUG enum fixed_addresses idx = type+KM_TYPE_NR*smp_processor_id(); - if ((vaddr & PAGE_MASK) == __fix_to_virt(FIX_KMAP_START+idx)) + if ((vaddr & PAGE_MASK) == __fix_to_virt(FIX_KMAP_BEGIN+idx)) { /* force other mappings to Oops if they'll try to access this pte without first remap it */ diff -urN 2.2.10-bigmem-D/mm/filemap.c 2.2.10-bigmem/mm/filemap.c --- 2.2.10-bigmem-D/mm/filemap.c Thu Aug 5 18:31:08 1999 +++ 2.2.10-bigmem/mm/filemap.c Sun Aug 8 01:46:31 1999 @@ -170,6 +170,11 @@ if ((gfp_mask & __GFP_DMA) && !PageDMA(page)) continue; +#ifdef CONFIG_BIGMEM + if (!(gfp_mask & __GFP_BIGMEM) && PageBIGMEM(page)) + continue; +#endif + /* We can't free pages unless there's just one user */ if (atomic_read(&page->count) != 1) continue; diff -urN 2.2.10-bigmem-D/mm/page_alloc.c 2.2.10-bigmem/mm/page_alloc.c --- 2.2.10-bigmem-D/mm/page_alloc.c Sat Aug 7 15:02:59 1999 +++ 2.2.10-bigmem/mm/page_alloc.c Sun Aug 8 01:59:11 1999 @@ -4,6 +4,7 @@ * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds * Swap reorganised 29.12.95, Stephen Tweedie * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 + * BIGMEM swapin, Andrea Arcangeli */ #include @@ -105,13 +106,16 @@ unsigned long index = map_nr >> (1 + order); unsigned long mask = (~0UL) << order; unsigned long flags; +#ifdef CONFIG_BIGMEM + extern unsigned long bigmem_mapnr; +#endif spin_lock_irqsave(&page_alloc_lock, flags); #define list(x) (mem_map+(x)) #ifdef CONFIG_BIGMEM - if (map_nr >= PHYSMAP_NR(bigmem_start)) { + if (map_nr >= bigmem_mapnr) { area += BIGMEM_LISTS_OFFSET; nr_free_bigmem -= mask; } @@ -493,6 +497,39 @@ * this process. */ delete_from_swap_cache(page_map); +#ifdef CONFIG_BIGMEM + /* this may looks ugly, but we want to use the bigmem pages as + much as possible. We can't do I/O over the bigmem pages so + we used a regular page to do the I/O but now we can replace + the regular page with a bigmem page if there is any bigmem + page available! fun ;) */ + if (!PageBIGMEM(page_map) && nr_free_bigmem) + { + unsigned long bigmem_page; + + bigmem_page = __get_free_page(GFP_ATOMIC|GFP_BIGMEM); + if (bigmem_page) + { + unsigned long vaddr, cached_swap_entry; + + vaddr = kmap(page, KM_READ); + copy_page(bigmem_page, vaddr); + kunmap(vaddr, KM_READ); + + /* we can just forget the old page since + we stored its data into the new + bigmem_page. */ + cached_swap_entry = page_map->offset; + __free_page(page_map); + + /* put the bigmem page in place of the + previous page. */ + page = bigmem_page; + page_map = MAP_NR(bigmem_page) + mem_map; + page_map->offset = cached_swap_entry; + } + } +#endif set_pte(page_table, pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)))); return; } diff -urN 2.2.10-bigmem-D/mm/vmscan.c 2.2.10-bigmem/mm/vmscan.c --- 2.2.10-bigmem-D/mm/vmscan.c Thu Aug 5 17:52:17 1999 +++ 2.2.10-bigmem/mm/vmscan.c Sun Aug 8 01:58:48 1999 @@ -8,6 +8,7 @@ * Removed kswapd_ctl limits, and swap out as many pages as needed * to bring the system back to freepages.high: 2.4.97, Rik van Riel. * Version: $Id: vmscan.c,v 1.5 1998/02/23 22:14:28 sct Exp $ + * BIGMEM swapout, Andrea Arcangeli */ #include @@ -60,7 +61,10 @@ if (PageReserved(page_map) || PageLocked(page_map) || ((gfp_mask & __GFP_DMA) && !PageDMA(page_map)) - || PageBIGMEM(page_map)) +#ifdef CONFIG_BIGMEM + || (!(gfp_mask & __GFP_BIGMEM) && PageBIGMEM(page_map)) +#endif + ) return 0; /* @@ -149,6 +153,36 @@ entry = get_swap_page(); if (!entry) return 0; /* No swap space left */ + +#ifdef BIGMEM + /* this is a bigmem page so the future b_data addresses will + confuse the lowlevel device drivers so we must use a + regular page to swapout a bigmem page. */ + if (PageBIGMEM(page_map)) + { + unsigned long regular_page; + unsigned long vaddr; + + regular_page = __get_free_page(GFP_ATOMIC); + if (!regular_page) + /* don't forget to undo the swap entry reference + we hold here. (but do that in the slow path) */ + goto out_free_swap; + + vaddr = kmap(page, KM_READ); + copy_page(regular_page, vaddr); + kunmap(vaddr, KM_READ); + + /* ok, we can just forget about our bigmem page since + we stored its data into the new regular_page. */ + __free_page(page_map); + + /* put the regular page in place of the just released + bigmeme page. */ + page = regular_page; + page_map = MAP_NR(regular_page) + mem_map; + } +#endif vma->vm_mm->rss--; tsk->nswap++; @@ -165,6 +199,10 @@ __free_page(page_map); return 1; + + out_free_swap: + swap_free(entry); + return 0; } /*