فهرست منبع

[PATCH] Add API for flushing Anon pages

Currently, get_user_pages() returns fully coherent pages to the kernel for
anything other than anonymous pages.  This is a problem for things like
fuse and the SCSI generic ioctl SG_IO which can potentially wish to do DMA
to anonymous pages passed in by users.

The fix is to add a new memory management API: flush_anon_page() which
is used in get_user_pages() to make anonymous pages coherent.

Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Cc: Russell King <rmk@arm.linux.org.uk>
Cc: "David S. Miller" <davem@davemloft.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
James Bottomley 19 سال پیش
والد
کامیت
03beb07664
3فایلهای تغییر یافته به همراه17 افزوده شده و 0 حذف شده
  1. 9 0
      Documentation/cachetlb.txt
  2. 6 0
      include/linux/highmem.h
  3. 2 0
      mm/memory.c

+ 9 - 0
Documentation/cachetlb.txt

@@ -362,6 +362,15 @@ maps this page at its virtual address.
 	likely that you will need to flush the instruction cache
 	likely that you will need to flush the instruction cache
 	for copy_to_user_page().
 	for copy_to_user_page().
 
 
+  void flush_anon_page(struct page *page, unsigned long vmaddr)
+  	When the kernel needs to access the contents of an anonymous
+	page, it calls this function (currently only
+	get_user_pages()).  Note: flush_dcache_page() deliberately
+	doesn't work for an anonymous page.  The default
+	implementation is a nop (and should remain so for all coherent
+	architectures).  For incoherent architectures, it should flush
+	the cache of the page at vmaddr in the current user process.
+
   void flush_icache_range(unsigned long start, unsigned long end)
   void flush_icache_range(unsigned long start, unsigned long end)
   	When the kernel stores into addresses that it will execute
   	When the kernel stores into addresses that it will execute
 	out of (eg when loading modules), this function is called.
 	out of (eg when loading modules), this function is called.

+ 6 - 0
include/linux/highmem.h

@@ -7,6 +7,12 @@
 
 
 #include <asm/cacheflush.h>
 #include <asm/cacheflush.h>
 
 
+#ifndef ARCH_HAS_FLUSH_ANON_PAGE
+static inline void flush_anon_page(struct page *page, unsigned long vmaddr)
+{
+}
+#endif
+
 #ifdef CONFIG_HIGHMEM
 #ifdef CONFIG_HIGHMEM
 
 
 #include <asm/highmem.h>
 #include <asm/highmem.h>

+ 2 - 0
mm/memory.c

@@ -1071,6 +1071,8 @@ int get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
 			}
 			}
 			if (pages) {
 			if (pages) {
 				pages[i] = page;
 				pages[i] = page;
+
+				flush_anon_page(page, start);
 				flush_dcache_page(page);
 				flush_dcache_page(page);
 			}
 			}
 			if (vmas)
 			if (vmas)