[parisc-linux] RFC: mmap patch

Randolph Chung Randolph Chung <randolph@tausq.org>
Wed, 5 Mar 2003 22:32:01 -0800


Hi all,

Looking for some vm gurus to verify that this is correct. This fixes a
problem where the kernel-view of a page vs the user-view can get out of
sync because of the virtually tagged cache of PA. This fixes a bug
reported some time back where write(2)s to a mmaped fd doesn't get 
updated properly in the mmap'ed region.

Many thanks to willy for his advice in putting this together :)

This is tested on 2.5.64-pa1 on a500, but should also apply to 2.4.

Any comments before I apply?

randolph

Index: include/asm-parisc/cacheflush.h
===================================================================
RCS file: /var/cvs/linux-2.5/include/asm-parisc/cacheflush.h,v
retrieving revision 1.5
diff -u -p -r1.5 cacheflush.h
--- include/asm-parisc/cacheflush.h	6 Mar 2003 04:20:45 -0000	1.5
+++ include/asm-parisc/cacheflush.h	6 Mar 2003 06:35:41 -0000
@@ -67,13 +67,15 @@ flush_user_icache_range(unsigned long st
 #endif
 }
 
+extern void __flush_dcache_page(struct page *page);
+
 static inline void flush_dcache_page(struct page *page)
 {
 	if (page->mapping && list_empty(&page->mapping->i_mmap) &&
 			list_empty(&page->mapping->i_mmap_shared)) {
 		set_bit(PG_dcache_dirty, &page->flags);
 	} else {
-		flush_kernel_dcache_page(page_address(page));
+		__flush_dcache_page(page);
 	}
 }
 
Index: arch/parisc/kernel/cache.c
===================================================================
RCS file: /var/cvs/linux-2.5/arch/parisc/kernel/cache.c,v
retrieving revision 1.9
diff -u -p -r1.9 cache.c
--- arch/parisc/kernel/cache.c	5 Mar 2003 21:15:37 -0000	1.9
+++ arch/parisc/kernel/cache.c	6 Mar 2003 06:35:41 -0000
@@ -222,3 +222,42 @@ void disable_sr_hashing(void)
 
 	disable_sr_hashing_asm(srhash_type);
 }
+
+void __flush_dcache_page(struct page *page)
+{
+	struct mm_struct *mm = current->active_mm;
+	struct list_head *l;
+
+	flush_kernel_dcache_page(page_address(page));
+
+	if (!page->mapping)
+		return;
+
+	list_for_each(l, &page->mapping->i_mmap_shared) {
+		struct vm_area_struct *mpnt;
+		unsigned long off;
+
+		mpnt = list_entry(l, struct vm_area_struct, shared);
+
+		/*
+		 * If this VMA is not in our MM, we can ignore it.
+		 */
+		if (mpnt->vm_mm != mm)
+			continue;
+
+		if (page->index < mpnt->vm_pgoff)
+			continue;
+
+		off = page->index - mpnt->vm_pgoff;
+		if (off >= (mpnt->vm_end - mpnt->vm_start) >> PAGE_SHIFT)
+			continue;
+
+		flush_cache_page(mpnt, mpnt->vm_start + (off << PAGE_SHIFT));
+
+		/* All user shared mappings should be equivalently mapped,
+		 * so once we've flushed one we should be ok
+		 */
+		break;
+	}
+}
+
-- 
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/