lkml.org 
[lkml]   [2004]   [Apr]   [11]   [last100]   RSS Feed
Views: [more markup]  [less markup]  [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
DateSun, 11 Apr 2004 15:24:04 +0100 (BST)
FromHugh Dickins <>
Subject[PATCH] rmap 4 flush_dcache revisited
First of another batch of three rmap patches: not the batch which will
change rmap around, just a set of fixes to issues which arose with the
first batch, scarcely related to rmap itself.  Based on 2.6.5-mc4, but
apply easily to 2.6.5-mm4 (except fault-armv.c, where -mm4 has a prior
fix in that area).

rmap 4 flush_dcache_page revisited

Sorry to follow up on the same files so soon, but I realized that this
arch code has long been slightly unsafe (if SMP or PREEMPT), silly not
to fix it while we're here.

One of the callers of flush_dcache_page is do_generic_mapping_read,
where file is read without i_sem and without page lock: concurrent
truncation may at any moment remove page from cache, NULLing ->mapping,
making flush_dcache_page liable to oops.  Put result of page_mapping in
a local variable and apply mapping_mapped to that (if we were to check
for NULL within mapping_mapped, it's unclear whether to say yes or no).

parisc and arm do have other locking unsafety in their i_mmap(_shared)
searching, but that's a larger issue to be dealt with down the line.

 arch/arm/mm/fault-armv.c        |   13 +++++++++----
 arch/mips/mm/cache.c            |    3 ++-
 arch/parisc/kernel/cache.c      |    7 ++++---
 arch/sparc64/mm/init.c          |    3 ++-
 include/asm-arm/cacheflush.h    |    4 +++-
 include/asm-parisc/cacheflush.h |    4 +++-
 include/asm-sh/pgalloc.h        |    7 +++----
 7 files changed, 26 insertions(+), 15 deletions(-)
--- 2.6.5-mc4/arch/arm/mm/fault-armv.c	2004-04-11 07:19:15.991662984 +0100
+++ rmap4/arch/arm/mm/fault-armv.c	2004-04-11 10:37:55.817550872 +0100
@@ -186,19 +186,20 @@ no_pmd:
 
 void __flush_dcache_page(struct page *page)
 {
+	struct address_space *mapping = page_mapping(page);
 	struct mm_struct *mm = current->active_mm;
 	struct list_head *l;
 
 	__cpuc_flush_dcache_page(page_address(page));
 
-	if (!page_mapping(page))
+	if (!mapping)
 		return;
 
 	/*
 	 * With a VIVT cache, we need to also write back
 	 * and invalidate any user data.
 	 */
-	list_for_each(l, &page->mapping->i_mmap_shared) {
+	list_for_each(l, &mapping->i_mmap_shared) {
 		struct vm_area_struct *mpnt;
 		unsigned long off;
 
@@ -224,17 +225,21 @@ void __flush_dcache_page(struct page *pa
 static void
 make_coherent(struct vm_area_struct *vma, unsigned long addr, struct page *page, int dirty)
 {
-	struct list_head *l;
+	struct address_space *mapping = page_mapping(page);
 	struct mm_struct *mm = vma->vm_mm;
+	struct list_head *l;
 	unsigned long pgoff = (addr - vma->vm_start) >> PAGE_SHIFT;
 	int aliases = 0;
 
+	if (!mapping)
+		return;
+
 	/*
 	 * If we have any shared mappings that are in the same mm
 	 * space, then we need to handle them specially to maintain
 	 * cache coherency.
 	 */
-	list_for_each(l, &page->mapping->i_mmap_shared) {
+	list_for_each(l, &mapping->i_mmap_shared) {
 		struct vm_area_struct *mpnt;
 		unsigned long off;
 
--- 2.6.5-mc4/arch/mips/mm/cache.c	2004-04-11 07:19:17.312462192 +0100
+++ rmap4/arch/mips/mm/cache.c	2004-04-11 10:37:55.818550720 +0100
@@ -55,9 +55,10 @@ asmlinkage int sys_cacheflush(void *addr
 
 void flush_dcache_page(struct page *page)
 {
+	struct address_space *mapping = page_mapping(page);
 	unsigned long addr;
 
-	if (page_mapping(page) && !mapping_mapped(page->mapping)) {
+	if (mapping && !mapping_mapped(mapping)) {
 		SetPageDcacheDirty(page);
 		return;
 	}
--- 2.6.5-mc4/arch/parisc/kernel/cache.c	2004-04-11 07:19:17.322460672 +0100
+++ rmap4/arch/parisc/kernel/cache.c	2004-04-11 10:37:55.819550568 +0100
@@ -229,16 +229,17 @@ void disable_sr_hashing(void)
 
 void __flush_dcache_page(struct page *page)
 {
+	struct address_space *mapping = page_mapping(page);
 	struct mm_struct *mm = current->active_mm;
 	struct list_head *l;
 
 	flush_kernel_dcache_page(page_address(page));
 
-	if (!page_mapping(page))
+	if (!mapping)
 		return;
 	/* check shared list first if it's not empty...it's usually
 	 * the shortest */
-	list_for_each(l, &page->mapping->i_mmap_shared) {
+	list_for_each(l, &mapping->i_mmap_shared) {
 		struct vm_area_struct *mpnt;
 		unsigned long off;
 
@@ -267,7 +268,7 @@ void __flush_dcache_page(struct page *pa
 
 	/* then check private mapping list for read only shared mappings
 	 * which are flagged by VM_MAYSHARE */
-	list_for_each(l, &page->mapping->i_mmap) {
+	list_for_each(l, &mapping->i_mmap) {
 		struct vm_area_struct *mpnt;
 		unsigned long off;
 
--- 2.6.5-mc4/arch/sparc64/mm/init.c	2004-04-11 07:19:17.961363544 +0100
+++ rmap4/arch/sparc64/mm/init.c	2004-04-11 10:37:55.821550264 +0100
@@ -224,10 +224,11 @@ void update_mmu_cache(struct vm_area_str
 
 void flush_dcache_page(struct page *page)
 {
+	struct address_space *mapping = page_mapping(page);
 	int dirty = test_bit(PG_dcache_dirty, &page->flags);
 	int dirty_cpu = dcache_dirty_cpu(page);
 
-	if (page_mapping(page) && !mapping_mapped(page->mapping)) {
+	if (mapping && !mapping_mapped(mapping)) {
 		if (dirty) {
 			if (dirty_cpu == smp_processor_id())
 				return;
--- 2.6.5-mc4/include/asm-arm/cacheflush.h	2004-04-11 07:19:22.378692008 +0100
+++ rmap4/include/asm-arm/cacheflush.h	2004-04-11 10:37:55.823549960 +0100
@@ -295,7 +295,9 @@ extern void __flush_dcache_page(struct p
 
 static inline void flush_dcache_page(struct page *page)
 {
-	if (page_mapping(page) && !mapping_mapped(page->mapping))
+	struct address_space *mapping = page_mapping(page);
+
+	if (mapping && !mapping_mapped(mapping))
 		set_bit(PG_dcache_dirty, &page->flags);
 	else
 		__flush_dcache_page(page);
--- 2.6.5-mc4/include/asm-parisc/cacheflush.h	2004-04-11 07:19:22.804627256 +0100
+++ rmap4/include/asm-parisc/cacheflush.h	2004-04-11 10:37:55.823549960 +0100
@@ -69,7 +69,9 @@ extern void __flush_dcache_page(struct p
 
 static inline void flush_dcache_page(struct page *page)
 {
-	if (page_mapping(page) && !mapping_mapped(page->mapping)) {
+	struct address_space *mapping = page_mapping(page);
+
+	if (mapping && !mapping_mapped(mapping)) {
 		set_bit(PG_dcache_dirty, &page->flags);
 	} else {
 		__flush_dcache_page(page);
--- 2.6.5-mc4/include/asm-sh/pgalloc.h	2004-04-11 07:19:23.002597160 +0100
+++ rmap4/include/asm-sh/pgalloc.h	2004-04-11 10:37:55.824549808 +0100
@@ -97,12 +97,11 @@ static inline pte_t ptep_get_and_clear(p
 
 	pte_clear(ptep);
 	if (!pte_not_present(pte)) {
-		struct page *page;
 		unsigned long pfn = pte_pfn(pte);
 		if (pfn_valid(pfn)) {
-			page = pfn_to_page(pfn);
-			if (!page_mapping(page) ||
-			    !mapping_writably_mapped(page->mapping))
+			struct page *page = pfn_to_page(pfn);
+			struct address_space *mapping = page_mapping(page);
+			if (!mapping || !mapping_writably_mapped(mapping))
 				__clear_bit(PG_mapped, &page->flags);
 		}
 	}
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:02    [from the cache]
©2003-2008