Chase down and fix a memory stomper in reconstitute_ptes(). Lots of debugging noise to be removed later. diff -prauN pgcl-2.5.70-bk14-1/Makefile pgcl-2.5.70-bk14-2/Makefile --- pgcl-2.5.70-bk14-1/Makefile 2003-06-09 07:49:56.000000000 -0700 +++ pgcl-2.5.70-bk14-2/Makefile 2003-06-09 12:30:17.000000000 -0700 @@ -216,7 +216,7 @@ NOSTDINC_FLAGS = -nostdinc -iwithprefix CPPFLAGS := -D__KERNEL__ -Iinclude CFLAGS := $(CPPFLAGS) -Wall -Wstrict-prototypes -Wno-trigraphs -O2 \ - -fno-strict-aliasing -fno-common + -fno-strict-aliasing -fno-common -g AFLAGS := -D__ASSEMBLY__ $(CPPFLAGS) export VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \ diff -prauN pgcl-2.5.70-bk14-1/include/asm-i386/tlb.h pgcl-2.5.70-bk14-2/include/asm-i386/tlb.h --- pgcl-2.5.70-bk14-1/include/asm-i386/tlb.h 2003-06-09 07:52:02.000000000 -0700 +++ pgcl-2.5.70-bk14-2/include/asm-i386/tlb.h 2003-06-09 11:06:23.000000000 -0700 @@ -19,6 +19,7 @@ #define PG_PTE PG_arch_1 #define NR_PTE 128 +#define FREE_PTE_NR NR_PTE #define NR_NONPTE 512 #define MAX_ZONE_ID (MAX_NUMNODES * MAX_NR_ZONES) diff -prauN pgcl-2.5.70-bk14-1/mm/memory.c pgcl-2.5.70-bk14-2/mm/memory.c --- pgcl-2.5.70-bk14-1/mm/memory.c 2003-06-09 07:52:47.000000000 -0700 +++ pgcl-2.5.70-bk14-2/mm/memory.c 2003-06-10 00:16:48.000000000 -0700 @@ -36,8 +36,6 @@ * (Gerhard.Wichert@pdb.siemens.de) */ -#define DEBUG 1 - #include #include #include @@ -67,6 +65,9 @@ unsigned long num_physpages; void * high_memory; struct page *highmem_start_page; +void check_rt_hash(void); +int check_rt_addr(void *); + /* * We special-case the C-O-W ZERO_PAGE, because it's such * a common occurrence (no need to read the page to know @@ -1020,6 +1021,7 @@ int remap_page_range(struct vm_area_stru static inline void establish_pte(struct vm_area_struct * vma, unsigned long address, pte_t *page_table, pte_t entry) { BUG_ON((unsigned long)page_table > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)page_table < PAGE_OFFSET); set_pte(page_table, entry); flush_tlb_page(vma, address); update_mmu_cache(vma, address, entry); @@ -1028,10 +1030,11 @@ static inline void establish_pte(struct /* * We hold the mm semaphore for reading and vma->vm_mm->page_table_lock */ -static inline void break_cow(struct vm_area_struct * vma, struct page * new_page, unsigned long address, pte_t *page_table, unsigned long subpfn) +static void break_cow(struct vm_area_struct * vma, struct page * new_page, unsigned long address, pte_t *page_table, unsigned long subpfn) { pte_t pte = pfn_pte(page_to_pfn(new_page) + subpfn, vma->vm_page_prot); BUG_ON((unsigned long)page_table > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)page_table < PAGE_OFFSET); invalidate_vcache(address, vma->vm_mm, new_page); flush_cache_page(vma, address); establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(pte))); @@ -1042,6 +1045,7 @@ static pte_t *fill_anonymizable_ptevec(s pte_t *ptes[], unsigned long addr, int map_pte, int cow) { + int k; unsigned long lo_vaddr, hi_vaddr, dn_vaddr, up_vaddr, dn_subpfn, up_subpfn, rss = 0, loop; pte_t *up_pte, *dn_pte; @@ -1111,6 +1115,21 @@ static pte_t *fill_anonymizable_ptevec(s } while ((up_vaddr < hi_vaddr || dn_vaddr >= lo_vaddr) && loop && up_subpfn >= dn_subpfn); + for (k = 0; k < PAGE_MMUCOUNT; ++k) { + if (!ptes[k]) + continue; + BUG_ON((unsigned long)ptes[k] > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)ptes[k] < PAGE_OFFSET); + BUG_ON(check_rt_addr(ptes[k])); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[k]) > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[k]) < PAGE_OFFSET); +#ifndef CONFIG_DISCONTIGMEM + BUG_ON((kmap_atomic_to_page(ptes[k]) - mem_map) >= max_mapnr); +#endif + BUG_ON(check_rt_addr(kmap_atomic_to_page(ptes[k]))); + BUG_ON(ptep_to_address(ptes[k]) >= MM_VM_SIZE(vma->vm_mm)); + } + pr_debug("finishing PTE search loop\n"); pr_debug("starting PTE instantiation loop\n"); pr_debug("fill_anonymizable_ptevec() saw %lu ptes set\n", rss); @@ -1171,11 +1190,23 @@ static void get_cow_pages(struct vm_area pr_debug("get_cow_pages()\n"); for (k = 0; k < PAGE_MMUCOUNT; ++k) { + if (!ptes[k]) { + pfns[k] = 0; + continue; + } + BUG_ON((unsigned long)ptes[k] > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)ptes[k] < PAGE_OFFSET); + BUG_ON(check_rt_addr(ptes[k])); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[k]) > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[k]) < PAGE_OFFSET); +#ifndef CONFIG_DISCONTIGMEM + BUG_ON((kmap_atomic_to_page(ptes[k]) - mem_map) >= max_mapnr); +#endif + BUG_ON(check_rt_addr(kmap_atomic_to_page(ptes[k]))); + BUG_ON(ptep_to_address(ptes[k]) >= MM_VM_SIZE(vma->vm_mm)); - if (!ptes[k]) - pfns[k] = 0; - else if (pte_present(*ptes[k])) { + if (pte_present(*ptes[k])) { if (pte_write(*ptes[k])) pr_debug("writable pte in get_cow_pages()!\n"); pfns[k] = pte_pfn(*ptes[k]); @@ -1223,12 +1254,23 @@ static void save_ptes(pte_t *ptes[], pte int k, rss = 0; pr_debug("save_ptes()\n"); for (k = 0; k < PAGE_MMUCOUNT; ++k) { + if (!ptes[k]) + continue; + BUG_ON((unsigned long)ptes[k] > (unsigned long)(-PAGE_SIZE)); - if (ptes[k]) { - ptevals[k] = *ptes[k]; - ptes[k] = (pte_t *)ptep_to_address(ptes[k]); - ++rss; - } + BUG_ON((unsigned long)ptes[k] < PAGE_OFFSET); + BUG_ON(check_rt_addr(ptes[k])); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[k]) > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[k]) < PAGE_OFFSET); +#ifndef CONFIG_DISCONTIGMEM + BUG_ON((kmap_atomic_to_page(ptes[k]) - mem_map) >= max_mapnr); +#endif + BUG_ON(check_rt_addr(kmap_atomic_to_page(ptes[k]))); + BUG_ON(ptep_to_address(ptes[k]) >= MM_VM_SIZE(vma->vm_mm)); + + ptevals[k] = *ptes[k]; + ptes[k] = (pte_t *)ptep_to_address(ptes[k]); + ++rss; } pr_debug("return from save_ptes()\n"); pr_debug("erm, save_ptes() saw %d ptes set!\n", rss); @@ -1251,15 +1293,47 @@ static pte_t *reconstitute_ptes(pmd_t *p */ if (j >= PAGE_MMUCOUNT) return NULL; + addr = (unsigned long)ptes[j]; + BUG_ON(addr >= MM_VM_SIZE(vma->vm_mm)); + ptes[j] = pte_offset_map(pmd, addr); + BUG_ON((unsigned long)ptes[j] > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)ptes[j] < PAGE_OFFSET); + BUG_ON(check_rt_addr(ptes[j])); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[j]) > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[j]) < PAGE_OFFSET); +#ifndef CONFIG_DISCONTIGMEM + BUG_ON((kmap_atomic_to_page(ptes[j]) - mem_map) >= max_mapnr); +#endif + BUG_ON(check_rt_addr(kmap_atomic_to_page(ptes[j]))); + BUG_ON(ptep_to_address(ptes[j]) >= MM_VM_SIZE(vma->vm_mm)); for (k = j + 1; k < PAGE_MMUCOUNT; ++k) { + unsigned long vaddr; + + if (!ptes[k]) + continue; + + vaddr = (unsigned long)ptes[k]; + BUG_ON(vaddr == addr); + + if (vaddr < addr) + ptes[k] = ptes[j] - (addr - vaddr)/MMUPAGE_SIZE; + else + ptes[k] = ptes[j] + (vaddr - addr)/MMUPAGE_SIZE; + BUG_ON((unsigned long)ptes[k] > (unsigned long)(-PAGE_SIZE)); - if (ptes[k]) - ptes[k] = ptes[j] + - ((unsigned long)ptes[k] - addr)/MMUPAGE_SIZE; + BUG_ON((unsigned long)ptes[k] < PAGE_OFFSET); + BUG_ON(check_rt_addr(ptes[k])); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[k]) > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[k]) < PAGE_OFFSET); +#ifndef CONFIG_DISCONTIGMEM + BUG_ON((kmap_atomic_to_page(ptes[k]) - mem_map) >= max_mapnr); +#endif + BUG_ON(check_rt_addr(kmap_atomic_to_page(ptes[k]))); + BUG_ON(ptep_to_address(ptes[k]) >= MM_VM_SIZE(vma->vm_mm)); } pr_debug("return 0x%p from reconstitute_ptes()\n", ptes[j]); return ptes[j]; @@ -1271,10 +1345,21 @@ static int recheck_ptes(pte_t *ptes[], u pr_debug("recheck_ptes()\n"); for (k = 0; k < PAGE_MMUCOUNT; ++k) { - BUG_ON((unsigned long)ptes[k] > (unsigned long)(-PAGE_SIZE)); if (!ptes[k] || !pfns[k]) continue; - else if (pte_same(*ptes[k], ptevals[k])) + + BUG_ON((unsigned long)ptes[k] > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)ptes[k] < PAGE_OFFSET); + BUG_ON(check_rt_addr(ptes[k])); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[k]) > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[k]) < PAGE_OFFSET); +#ifndef CONFIG_DISCONTIGMEM + BUG_ON((kmap_atomic_to_page(ptes[k]) - mem_map) >= max_mapnr); +#endif + BUG_ON(check_rt_addr(kmap_atomic_to_page(ptes[k]))); + BUG_ON(ptep_to_address(ptes[k]) >= MM_VM_SIZE(vma->vm_mm)); + + if (pte_same(*ptes[k], ptevals[k])) ++rss; else { pr_debug("recheck_ptes() dropped racy pfn\n"); @@ -1299,35 +1384,76 @@ static void release_pfns(unsigned long p } static struct pte_chain *move_mappings(struct vm_area_struct *vma, - struct page *new_page, unsigned long address, + struct page *new_page, unsigned long pfns[], pte_t *ptes[], struct pte_chain *pte_chain) { unsigned long k; + BUG_ON(!vma); + BUG_ON((unsigned long)vma > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)vma < PAGE_OFFSET); + BUG_ON(check_rt_addr(vma)); + BUG_ON(!new_page); + BUG_ON((unsigned long)new_page > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)new_page < PAGE_OFFSET); + BUG_ON(check_rt_addr(new_page)); +#ifndef CONFIG_DISCONTIGMEM + BUG_ON((new_page - mem_map) >= max_mapnr); +#endif + pr_debug("move_mappings()\n"); for (k = 0; k < PAGE_MMUCOUNT; ++k) { struct page *page; int release; - BUG_ON((unsigned long)ptes[k] > (unsigned long)(-PAGE_SIZE)); + extern unsigned long max_pfn; if (!ptes[k] || !pfns[k]) continue; + BUG_ON((unsigned long)ptes[k] > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)ptes[k] < PAGE_OFFSET); + BUG_ON(check_rt_addr(ptes[k])); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[k]) > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)kmap_atomic_to_page(ptes[k]) < PAGE_OFFSET); +#ifndef CONFIG_DISCONTIGMEM + BUG_ON((kmap_atomic_to_page(ptes[k]) - mem_map) >= max_mapnr); +#endif + BUG_ON(check_rt_addr(kmap_atomic_to_page(ptes[k]))); + BUG_ON(ptep_to_address(ptes[k]) >= MM_VM_SIZE(vma->vm_mm)); + BUG_ON(pfns[k] > max_pfn); + release = pte_present(*ptes[k]); page = pfn_valid(pfns[k]) ? pfn_to_page(pfns[k]) : NULL; if (page) { - if (PageReserved(page)) - ptep_to_mm(ptes[k])->rss++; - else +#ifndef CONFIG_DISCONTIGMEM + BUG_ON((page - mem_map) >= max_mapnr); +#endif + BUG_ON(check_rt_addr(page)); + if (PageReserved(page)) { + struct mm_struct *mm = ptep_to_mm(ptes[k]); + BUG_ON(!mm); + BUG_ON((unsigned long)mm > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)mm < PAGE_OFFSET); + mm->rss++; + } else page_remove_rmap(page, ptes[k]); } - break_cow(vma, new_page, address, ptes[k], k); + break_cow(vma, new_page, ptep_to_address(ptes[k]), ptes[k], k); + BUG_ON(!pte_chain); + BUG_ON((unsigned long)pte_chain > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)pte_chain < PAGE_OFFSET); + BUG_ON(check_rt_addr(pte_chain)); pte_chain = page_add_rmap_chained(new_page,ptes[k],pte_chain); /* nuke the pte's reference since we retargeted the pte */ - if (page && release) + if (page && release && !PageReserved(page)) page_cache_release(page); } + if (pte_chain) { + BUG_ON((unsigned long)pte_chain > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)pte_chain < PAGE_OFFSET); + BUG_ON(check_rt_addr(pte_chain)); + } pr_debug("return 0x%p from move_mappings()\n", pte_chain); return pte_chain; } @@ -1403,6 +1529,7 @@ static int do_wp_page(struct mm_struct * /* get all the relevant pages */ pr_debug("calling get_cow_pages()\n"); get_cow_pages(vma, pfns, ptes); + /* save all the ptes */ pr_debug("calling save_ptes()\n"); save_ptes(ptes, ptevals); @@ -1455,7 +1582,7 @@ static int do_wp_page(struct mm_struct * goto out; } pr_debug("calling move_mappings()\n"); - pte_chain = move_mappings(vma,new_page,address,pfns,ptes,pte_chain); + pte_chain = move_mappings(vma, new_page, pfns, ptes, pte_chain); atomic_add(rss, &new_page->count); pr_debug("do_wp_page() returning VM_FAULT_MINOR\n"); @@ -1469,7 +1596,6 @@ static int do_wp_page(struct mm_struct * release_pfns(pfns); page_cache_release(new_page); ret = VM_FAULT_MINOR; - goto out; out: spin_unlock(&mm->page_table_lock); diff -prauN pgcl-2.5.70-bk14-1/mm/rmap.c pgcl-2.5.70-bk14-2/mm/rmap.c --- pgcl-2.5.70-bk14-1/mm/rmap.c 2003-06-09 14:52:01.000000000 -0700 +++ pgcl-2.5.70-bk14-2/mm/rmap.c 2003-06-09 15:24:19.000000000 -0700 @@ -173,13 +173,16 @@ page_add_rmap(struct page *page, pte_t * BUG_ON(!pte_chain); BUG_ON((unsigned long)pte_chain < PAGE_OFFSET); BUG_ON((unsigned long)pte_chain > (unsigned long)(-PAGE_SIZE)); - BUG_ON(!page); - BUG_ON((unsigned long)page < PAGE_OFFSET); - BUG_ON((unsigned long)page > (unsigned long)(-PAGE_SIZE)); BUG_ON(!ptep); BUG_ON((unsigned long)ptep < PAGE_OFFSET); BUG_ON((unsigned long)ptep > (unsigned long)(-PAGE_SIZE)); BUG_ON(pte_chain->next_and_idx); + BUG_ON(!page); + BUG_ON((unsigned long)page < PAGE_OFFSET); + BUG_ON((unsigned long)page > (unsigned long)(-PAGE_SIZE)); +#ifndef CONFIG_DISCONTIGMEM + BUG_ON((page - mem_map) >= max_mapnr); +#endif if (!pfn_valid(page_to_pfn(page)) || PageReserved(page)) return pte_chain; @@ -236,6 +239,9 @@ page_add_rmap_chained(struct page *page, BUG_ON(!page); BUG_ON((unsigned long)page < PAGE_OFFSET); BUG_ON((unsigned long)page > (unsigned long)(-PAGE_SIZE)); +#ifndef CONFIG_DISCONTIGMEM + BUG_ON((page - mem_map) >= max_mapnr); +#endif rest = pte_chain_next(pc); pc->next_and_idx = 0; @@ -272,9 +278,6 @@ void page_remove_rmap(struct page *page, #ifndef CONFIG_DISCONTIGMEM BUG_ON((page - mem_map) >= max_mapnr); #endif - BUG_ON(!ptep); - BUG_ON((unsigned long)ptep < PAGE_OFFSET); - BUG_ON((unsigned long)ptep > (unsigned long)(-PAGE_SIZE)); if (!pfn_valid(page_to_pfn(page)) || PageReserved(page)) return; @@ -596,8 +599,8 @@ struct pte_chain *pte_chain_alloc(int gf } if (ret) { - BUG_ON((unsigned long)pc < PAGE_OFFSET); - BUG_ON((unsigned long)pc > (unsigned long)(-PAGE_SIZE)); + BUG_ON((unsigned long)ret < PAGE_OFFSET); + BUG_ON((unsigned long)ret > (unsigned long)(-PAGE_SIZE)); } return ret; } diff -prauN pgcl-2.5.70-bk14-1/net/ipv4/route.c pgcl-2.5.70-bk14-2/net/ipv4/route.c --- pgcl-2.5.70-bk14-1/net/ipv4/route.c 2003-06-09 07:50:02.000000000 -0700 +++ pgcl-2.5.70-bk14-2/net/ipv4/route.c 2003-06-09 15:58:26.000000000 -0700 @@ -513,6 +513,11 @@ static void rt_run_flush(unsigned long d for (i = rt_hash_mask; i >= 0; i--) { spin_lock_bh(&rt_hash_table[i].lock); rth = rt_hash_table[i].chain; + if (rth && (unsigned long)rth < PAGE_OFFSET) { + WARN_ON(1); + rth = NULL; + rt_hash_table[i].chain = NULL; + } if (rth) rt_hash_table[i].chain = NULL; spin_unlock_bh(&rt_hash_table[i].lock); @@ -643,6 +648,12 @@ static int rt_garbage_collect(void) for (i = rt_hash_mask, k = rover; i >= 0; i--) { unsigned long tmo = expire; + if (rt_hash_table[k].chain && + (unsigned long)rt_hash_table[k].chain < PAGE_OFFSET) { + WARN_ON(1); + rt_hash_table[k].chain = NULL; + } + k = (k + 1) & rt_hash_mask; rthp = &rt_hash_table[k].chain; spin_lock_bh(&rt_hash_table[k].lock); @@ -722,6 +733,11 @@ static int rt_intern_hash(unsigned hash, int attempts = !in_softirq(); restart: + if (rt_hash_table[hash].chain && + (unsigned long)rt_hash_table[hash].chain < PAGE_OFFSET) { + WARN_ON(1); + rt_hash_table[hash].chain = NULL; + } rthp = &rt_hash_table[hash].chain; spin_lock_bh(&rt_hash_table[hash].lock); @@ -802,6 +818,7 @@ restart: printk("\n"); } #endif + BUG_ON(rt && (unsigned long)rt < PAGE_OFFSET); rt_hash_table[hash].chain = rt; spin_unlock_bh(&rt_hash_table[hash].lock); *rp = rt; @@ -872,6 +889,11 @@ static void rt_del(unsigned hash, struct spin_lock_bh(&rt_hash_table[hash].lock); ip_rt_put(rt); + if (rt_hash_table[hash].chain && + (unsigned long)rt_hash_table[hash].chain < PAGE_OFFSET) { + WARN_ON(1); + rt_hash_table[hash].chain = NULL; + } for (rthp = &rt_hash_table[hash].chain; *rthp; rthp = &(*rthp)->u.rt_next) if (*rthp == rt) { @@ -916,6 +938,11 @@ void ip_rt_redirect(u32 old_gw, u32 dadd skeys[i] ^ (ikeys[k] << 5), tos); + if (rt_hash_table[hash].chain && + (unsigned long)rt_hash_table[hash].chain < PAGE_OFFSET) { + WARN_ON(1); + rt_hash_table[hash].chain = NULL; + } rthp=&rt_hash_table[hash].chain; rcu_read_lock(); @@ -1172,6 +1199,11 @@ unsigned short ip_rt_frag_needed(struct unsigned hash = rt_hash_code(daddr, skeys[i], tos); rcu_read_lock(); + if (rt_hash_table[hash].chain && + (unsigned long)rt_hash_table[hash].chain < PAGE_OFFSET) { + WARN_ON(1); + rt_hash_table[hash].chain = NULL; + } for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) { smp_read_barrier_depends(); @@ -1768,6 +1800,11 @@ int ip_route_input(struct sk_buff *skb, hash = rt_hash_code(daddr, saddr ^ (iif << 5), tos); rcu_read_lock(); + if (rt_hash_table[hash].chain && + (unsigned long)rt_hash_table[hash].chain < PAGE_OFFSET) { + WARN_ON(1); + rt_hash_table[hash].chain = NULL; + } for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) { smp_read_barrier_depends(); if (rth->fl.fl4_dst == daddr && @@ -2134,6 +2171,11 @@ int __ip_route_output_key(struct rtable hash = rt_hash_code(flp->fl4_dst, flp->fl4_src ^ (flp->oif << 5), flp->fl4_tos); rcu_read_lock(); + if (rt_hash_table[hash].chain && + (unsigned long)rt_hash_table[hash].chain < PAGE_OFFSET) { + WARN_ON(1); + rt_hash_table[hash].chain = NULL; + } for (rth = rt_hash_table[hash].chain; rth; rth = rth->u.rt_next) { smp_read_barrier_depends(); if (rth->fl.fl4_dst == flp->fl4_dst && @@ -2365,6 +2407,11 @@ int ip_rt_dump(struct sk_buff *skb, str if (h > s_h) s_idx = 0; rcu_read_lock(); + if (rt_hash_table[h].chain && + (unsigned long)rt_hash_table[h].chain < PAGE_OFFSET) { + WARN_ON(1); + rt_hash_table[h].chain = NULL; + } for (rt = rt_hash_table[h].chain, idx = 0; rt; rt = rt->u.rt_next, idx++) { smp_read_barrier_depends(); @@ -2636,6 +2683,31 @@ static int ip_rt_acct_read(char *buffer, #endif /* CONFIG_PROC_FS */ #endif /* CONFIG_NET_CLS_ROUTE */ +void check_rt_hash(void) +{ + int k; + rcu_read_lock(); + for (k = 0; k <= rt_hash_mask; ++k) { + if (!rt_hash_table[k].chain) + continue; + if ((unsigned long)rt_hash_table[k].chain > PAGE_OFFSET + && (unsigned long)rt_hash_table[k].chain < (unsigned long)(-PAGE_SIZE)) + continue; + dump_stack(); + rt_hash_table[k].chain = NULL; + } + rcu_read_unlock(); +} + +int check_rt_addr(void *addr) +{ + unsigned long vaddr = (unsigned long)addr; + unsigned long hash = (unsigned long)((void *)&rt_hash_table[0]); + if (vaddr < hash) + return 0; + return vaddr - hash <= sizeof(struct rt_hash_bucket)*rt_hash_mask; +} + int __init ip_rt_init(void) { int i, order, goal, rc = 0; @@ -2686,6 +2758,9 @@ int __init ip_rt_init(void) /* NOTHING */; rt_hash_mask--; + + WARN_ON(sizeof(struct rt_hash_bucket)*rt_hash_mask>=(PAGE_SIZE<