diff -prauN pgcl-2.5.68-1F/include/asm-generic/rmap.h pgcl-2.5.68-1G/include/asm-generic/rmap.h --- pgcl-2.5.68-1F/include/asm-generic/rmap.h 2003-04-27 21:28:42.000000000 -0700 +++ pgcl-2.5.68-1G/include/asm-generic/rmap.h 2003-04-28 20:12:37.000000000 -0700 @@ -61,11 +61,12 @@ static inline void pgtable_add_rmap(stru static inline void pgtable_remove_rmap(struct page *page) { - /* rmap's accounting is alrady torn down */ - if (!page->mapping) { - /* this can't catch them all */ - WARN_ON(page->index); - return; + /* we're not down to a unique reference */ + if (PAGE_MMUCOUNT > 1) { + if (atomic_read(&page->count) > 1) + return; + else + WARN_ON(atomic_read(&page->count) <= 0); } page->mapping = NULL; diff -prauN pgcl-2.5.68-1F/include/asm-i386/pgalloc.h pgcl-2.5.68-1G/include/asm-i386/pgalloc.h --- pgcl-2.5.68-1F/include/asm-i386/pgalloc.h 2003-04-27 23:25:05.000000000 -0700 +++ pgcl-2.5.68-1G/include/asm-i386/pgalloc.h 2003-04-28 20:10:02.000000000 -0700 @@ -7,10 +7,13 @@ #include #include #include /* for struct page */ +#include /* to make asm-generic/rmap.h happy */ +#include /* for pgtable_remove_rmap() */ #define pmd_populate_kernel(mm, pmd, pte) \ set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) +static inline void pgtable_remove_rmap(struct page *); static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page) { unsigned long pfn, pmd_off = (unsigned long)pmd; @@ -21,12 +24,47 @@ static inline void pmd_populate(struct m pmd -= pmd_off; if (PAGE_MMUCOUNT > 1) { + struct page *old_page = NULL; + int new_count = 0; + if (atomic_read(&page->count) != 1) { WARN_ON(1); printk(KERN_DEBUG "bad pte refcount = %d\n", atomic_read(&page->count)); } - atomic_set(&page->count, PAGE_MMUCOUNT); + + for (k = 0; k < PAGE_MMUCOUNT; ++k) { + if (pmd_present(pmd[k]) || !pmd_none(pmd[k])) { + if (old_page) + WARN_ON(old_page != pmd_page(pmd[k])); + else + old_page = pmd_page(pmd[k]); + ++new_count; + } + } + + if (!old_page) + atomic_set(&page->count, PAGE_MMUCOUNT); + else { + /* old_page->index can legitimately be 0 */ + WARN_ON((struct mm_struct *)old_page->mapping != mm); + WARN_ON((struct mm_struct *)page->mapping != mm); + /* if (old_page->mapping != mm) + pgtable_add_rmap(page, mm, page->index); */ + pgtable_remove_rmap(page); + put_page(page); + atomic_add(new_count, &old_page->count); + for (k = 0; k < PAGE_MMUCOUNT; ++k) { + unsigned long long pmdval; + pmdval = page_to_pfn(old_page) + k; + pmdval <<= MMUPAGE_SHIFT; + if (pmd_present(pmd[k]) || !pmd_none(pmd[k])) + continue; + else + set_pmd(&pmd[k], __pmd(_PAGE_TABLE + pmdval)); + } + return; + } } for (k = 0; k < PAGE_MMUCOUNT; ++k) { @@ -70,8 +108,12 @@ static inline void tlb_remove_page(struc static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *page) { /* restore the reference count so later frees don't BUG() */ - if (PAGE_MMUCOUNT > 1 && atomic_dec_and_test(&page->count)) - atomic_set(&page->count, 1); + if (PAGE_MMUCOUNT > 1) { + if (atomic_dec_and_test(&page->count)) + atomic_set(&page->count, 1); + else + return; + } tlb_remove_page(tlb, page); } diff -prauN pgcl-2.5.68-1F/mm/memory.c pgcl-2.5.68-1G/mm/memory.c --- pgcl-2.5.68-1F/mm/memory.c 2003-04-28 04:11:43.000000000 -0700 +++ pgcl-2.5.68-1G/mm/memory.c 2003-04-28 20:22:09.000000000 -0700 @@ -159,7 +159,7 @@ pte_t * pte_alloc_map(struct mm_struct * pte_free(new); goto out; } -#if 1 +#if 0 { int k; pmd_t *base;