Simplify some of the out-of-memory error recovery logic by passing lists of pte_chains around. -- wli diff -prauN pgcl-2.5.70-bk13-1/include/linux/swap.h pgcl-2.5.70-bk13-2/include/linux/swap.h --- pgcl-2.5.70-bk13-1/include/linux/swap.h 2003-06-08 06:20:34.000000000 -0700 +++ pgcl-2.5.70-bk13-2/include/linux/swap.h 2003-06-08 08:41:30.000000000 -0700 @@ -185,6 +185,10 @@ struct pte_chain *FASTCALL(page_add_rmap struct pte_chain *)); void FASTCALL(page_remove_rmap(struct page *, pte_t *)); int FASTCALL(try_to_unmap(struct page *)); +struct pte_chain *FASTCALL(pte_chain_alloc_chained(int)); +void FASTCALL(pte_chain_free_chained(struct pte_chain *)); +struct pte_chain *FASTCALL(page_add_rmap_chained(struct page *, pte_t *, + struct pte_chain *)); /* linux/mm/shmem.c */ extern int shmem_unuse(swp_entry_t entry, struct page *page); diff -prauN pgcl-2.5.70-bk13-1/mm/memory.c pgcl-2.5.70-bk13-2/mm/memory.c --- pgcl-2.5.70-bk13-1/mm/memory.c 2003-06-08 06:48:08.000000000 -0700 +++ pgcl-2.5.70-bk13-2/mm/memory.c 2003-06-08 08:54:25.000000000 -0700 @@ -1415,17 +1415,17 @@ do_anonymous_page(struct mm_struct *mm, page = ZERO_PAGE(addr); else { if (!pte_chain) - pte_chain = pte_chain_alloc(GFP_ATOMIC); + pte_chain = pte_chain_alloc_chained(GFP_ATOMIC); pte_unmap(page_table); spin_unlock(&mm->page_table_lock); if (!pte_chain) { - pte_chain = pte_chain_alloc(GFP_KERNEL); + pte_chain = pte_chain_alloc_chained(GFP_KERNEL); if (!pte_chain) return VM_FAULT_OOM; } page = alloc_page(GFP_HIGHUSER); if (!page) { - pte_chain_free(pte_chain); + pte_chain_free_chained(pte_chain); return VM_FAULT_OOM; } clear_user_highpage(page, addr); @@ -1507,67 +1507,13 @@ do_anonymous_page(struct mm_struct *mm, set_pte(ptes[subpfn], pte_wrprotect(pte)); } else { pr_debug("setting pte to newly zeroed anonymous page\n"); - if (!pte_chain) - pte_chain = pte_chain_alloc(GFP_ATOMIC); - if (!pte_chain) { - unsigned long vaddr, offset; - int k; - - pr_debug("doing sleeping alloc of pte_chain" - " for non-anonymous page\n"); - - vaddr = ptep_to_address(ptes[subpfn]); - - pr_debug("vaddr = 0x%lx\n", vaddr); - - pte_unmap(ptes[subpfn]); - spin_unlock(&mm->page_table_lock); - pte_chain = pte_chain_alloc(GFP_KERNEL); - if (!pte_chain) { - pr_debug("going to out_oom\n"); - ret = VM_FAULT_OOM; - mm->rss += rss; - goto out_oom; - } - spin_lock(&mm->page_table_lock); - page_table = pte_offset_map(pmd, vaddr); - - /* is this safe from gcc? NFI */ - if (page_table != ptes[subpfn]) { - pr_debug("(page_table) 0x%p != 0x%p" - " (ptes[subpfn])\n", - page_table, - ptes[subpfn]); - offset = (unsigned long) - (page_table - ptes[subpfn]); - pr_debug("adjusting all ptes by" - " offset 0x%lx\n", - offset); - for (k = subpfn; k < PAGE_MMUCOUNT; ++k) { - pr_debug("pte before 0x%p\n", - ptes[k]); - if (ptes[k]) - ptes[k] += offset; - pr_debug("pte after 0x%p\n", - ptes[k]); - } - } - - /* check for races */ - if (!pte_none(*ptes[subpfn]) && - pfn_valid(pte_pfn(*ptes[subpfn])) && - pte_page(*ptes[subpfn]) != - ZERO_PAGE(ptep_to_address(ptes[subpfn]))) { - pr_debug("raced, skipping PTE\n"); - continue; - } - } + BUG_ON(!pte_chain); pr_debug("setting pte for anonymous zeroed page\n"); pr_debug("ptep = 0x%p, pte = 0x%Lx\n", ptes[subpfn], (u64)pte_val(pte)); set_pte(ptes[subpfn], pte_mkwrite(pte_mkdirty(pte))); pr_debug("about to page_add_rmap()\n"); - pte_chain = page_add_rmap(page, ptes[subpfn], + pte_chain = page_add_rmap_chained(page, ptes[subpfn], pte_chain); pr_debug("about to update_mmu_cache()\n"); update_mmu_cache(vma, addr, pte); @@ -1583,8 +1529,6 @@ do_anonymous_page(struct mm_struct *mm, mm->rss += rss; spin_unlock(&mm->page_table_lock); pr_debug("broke out of PTE instantiation loop\n"); -out_oom: - pr_debug("at out_oom\n"); if (write_access) { if (rss) { pr_debug("adding page to LRU\n"); @@ -1595,7 +1539,7 @@ out_oom: page_cache_release(page); } pr_debug("doing pte_chain_free()\n"); - pte_chain_free(pte_chain); + pte_chain_free_chained(pte_chain); return ret; } @@ -1615,7 +1559,7 @@ static int do_no_page(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, int write_access, pte_t *page_table, pmd_t *pmd) { - struct page * new_page; + struct page *new_page; pte_t entry; struct pte_chain *pte_chain; int ret; diff -prauN pgcl-2.5.70-bk13-1/mm/rmap.c pgcl-2.5.70-bk13-2/mm/rmap.c --- pgcl-2.5.70-bk13-1/mm/rmap.c 2003-06-08 06:20:34.000000000 -0700 +++ pgcl-2.5.70-bk13-2/mm/rmap.c 2003-06-08 08:48:37.000000000 -0700 @@ -210,6 +210,19 @@ out: return pte_chain; } +struct pte_chain * +page_add_rmap_chained(struct page *page, pte_t *pte, struct pte_chain *pc) +{ + struct pte_chain *rest = pte_chain_next(pc); + pc->next_and_idx = 0; + pc = page_add_rmap(page, pte, pc); + if (pc) { + pc->next_and_idx = pte_chain_encode(rest, 0); + rest = pc; + } + return rest; +} + /** * page_remove_rmap - take down reverse mapping to a page * @page: page to remove mapping from @@ -522,6 +535,34 @@ struct pte_chain *pte_chain_alloc(int gf return ret; } +struct pte_chain *pte_chain_alloc_chained(int gfp_flags) +{ + int k; + struct pte_chain *ret = NULL; + + for (k = 0; k < PAGE_MMUCOUNT; ++k) { + struct pte_chain *tmp = pte_chain_alloc(gfp_flags); + if (tmp) { + tmp->next_and_idx = pte_chain_encode(ret, 0); + ret = tmp; + } else { + pte_chain_free_chained(ret); + return NULL; + } + } + return ret; +} + +void pte_chain_free_chained(struct pte_chain *pc) +{ + while (pc) { + struct pte_chain *next = pte_chain_next(pc); + pc->next_and_idx = 0; + pte_chain_free(pc); + pc = next; + } +} + void __init pte_chain_init(void) { pte_chain_cache = kmem_cache_create( "pte_chain",