Check for PageSlab in arch flush_dcache_page to avoid triggering VM_BUG_ON We added a VM_BUG_ON in include/linux/mm.h to detect page cache functions used on slab pages. However, arches that have virtual caches may call flush_dcache_page for slab pages since they may have been put on scatter gather lists. Modify the functions in the affected arches to check for PageSlab() and use a NULL mapping if such a page is encountered. This may only be necessary for parisc and arm since sparc64 and xtensa do not scan over processes mapping a page but I have modified those two arches also for correctnesses sake since they use page_mapping() in flush_dcache_page(). If we have done that then we no longer need to return a NULL mapping in page_mapping() for slab pages (Its a bit strange to have that given the earlier VM_BUG_ON(PageSlab(page)). Signed-off-by: Christoph Lameter Index: linux-2.6/arch/arm/mm/flush.c =================================================================== --- linux-2.6.orig/arch/arm/mm/flush.c 2007-01-10 19:33:45.000000000 -0800 +++ linux-2.6/arch/arm/mm/flush.c 2007-07-23 13:02:56.000000000 -0700 @@ -188,7 +188,17 @@ static void __flush_dcache_aliases(struc */ void flush_dcache_page(struct page *page) { - struct address_space *mapping = page_mapping(page); + struct address_space *mapping; + + /* + * This function is special in that a page struct obtained via + * virt_to_page from a slab object may be passed to it. However, slab + * allocators may use the mapping field for their own purposes. As a + * result mapping may be != NULL here although the page is not mapped. + * Slab objects are never mapped into user space so use NULL for that + * special case. + */ + mapping = PageSlab(page) ? NULL : page_mapping(page); #ifndef CONFIG_SMP if (mapping && !mapping_mapped(mapping)) Index: linux-2.6/arch/parisc/kernel/cache.c =================================================================== --- linux-2.6.orig/arch/parisc/kernel/cache.c 2007-05-22 11:42:42.000000000 -0700 +++ linux-2.6/arch/parisc/kernel/cache.c 2007-07-23 13:02:56.000000000 -0700 @@ -339,7 +339,7 @@ __flush_cache_page(struct vm_area_struct void flush_dcache_page(struct page *page) { - struct address_space *mapping = page_mapping(page); + struct address_space *mapping; struct vm_area_struct *mpnt; struct prio_tree_iter iter; unsigned long offset; @@ -347,6 +347,15 @@ void flush_dcache_page(struct page *page pgoff_t pgoff; unsigned long pfn = page_to_pfn(page); + /* + * This function is special in that a page struct obtained via + * virt_to_page from a slab object may be passed to it. However, slab + * allocators may use the mapping field for their own purposes. As a + * result mapping may be != NULL here although the page is not mapped. + * Slab objects are never mapped into user space so use NULL for that + * special case. + */ + mapping = PageSlab(page) ? NULL : page_mapping(page); if (mapping && !mapping_mapped(mapping)) { set_bit(PG_dcache_dirty, &page->flags); Index: linux-2.6/arch/sparc64/mm/init.c =================================================================== --- linux-2.6.orig/arch/sparc64/mm/init.c 2007-05-30 11:19:44.000000000 -0700 +++ linux-2.6/arch/sparc64/mm/init.c 2007-07-23 13:02:56.000000000 -0700 @@ -339,7 +339,15 @@ void flush_dcache_page(struct page *page this_cpu = get_cpu(); - mapping = page_mapping(page); + /* + * This function is special in that a page struct obtained via + * virt_to_page from a slab object may be passed to it. However, slab + * allocators may use the mapping field for their own purposes. As a + * result mapping may be != NULL here although the page is not mapped. + * Slab objects are never mapped into user space so use NULL for that + * special case. + */ + mapping = PageSlab(page) ? NULL : page_mapping(page); if (mapping && !mapping_mapped(mapping)) { int dirty = test_bit(PG_dcache_dirty, &page->flags); if (dirty) { Index: linux-2.6/arch/xtensa/mm/init.c =================================================================== --- linux-2.6.orig/arch/xtensa/mm/init.c 2007-06-07 19:25:13.000000000 -0700 +++ linux-2.6/arch/xtensa/mm/init.c 2007-07-23 13:02:56.000000000 -0700 @@ -433,7 +433,7 @@ void copy_user_page(void* to, void* from void flush_dcache_page(struct page *page) { unsigned long addr = __pa(page_address(page)); - struct address_space *mapping = page_mapping(page); + struct address_space *mapping; __flush_invalidate_dcache_page_phys(addr); @@ -442,6 +442,15 @@ void flush_dcache_page(struct page *page /* If this page hasn't been mapped, yet, handle I$/D$ coherency later.*/ #if 0 + /* + * This function is special in that a page struct obtained via + * virt_to_page from a slab object may be passed to it. However, slab + * allocators may use the mapping field for their own purposes. As a + * result mapping may be != NULL although the page is not mapped. + * Slab objects are never mapped into user space so use NULL for that + * special case. + */ + mapping = PageSlab(page) ? NULL : page_mapping(page); if (mapping && !mapping_mapped(mapping)) clear_bit(PG_cache_clean, &page->flags); else Index: linux-2.6/include/linux/mm.h =================================================================== --- linux-2.6.orig/include/linux/mm.h 2007-07-23 13:02:16.000000000 -0700 +++ linux-2.6/include/linux/mm.h 2007-07-23 13:03:22.000000000 -0700 @@ -630,10 +630,6 @@ static inline struct address_space *page VM_BUG_ON(PageSlab(page)); if (unlikely(PageSwapCache(page))) mapping = &swapper_space; -#ifdef CONFIG_SLUB - else if (unlikely(PageSlab(page))) - mapping = NULL; -#endif else if (unlikely((unsigned long)mapping & PAGE_MAPPING_ANON)) mapping = NULL; return mapping;