We're not allowed to do down_read() on the filemap_copy_from_user() path: the
caller has an atomic kmap.

Just fail the copy and let the filemap_copy_from_user() slow path recover.


 mm/usercopy.c |   10 ++++++++++
 1 files changed, 10 insertions(+)

diff -puN mm/usercopy.c~4g4g-pin_page-atomicity-fix mm/usercopy.c
--- 25/mm/usercopy.c~4g4g-pin_page-atomicity-fix	2003-08-30 15:42:19.000000000 -0700
+++ 25-akpm/mm/usercopy.c	2003-08-30 15:42:19.000000000 -0700
@@ -15,6 +15,7 @@
 #include <linux/pagemap.h>
 #include <linux/smp_lock.h>
 #include <linux/ptrace.h>
+#include <linux/interrupt.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
@@ -46,6 +47,15 @@ static inline struct page *pin_page(unsi
 	 */
 	spin_unlock(&mm->page_table_lock);
 
+	/*
+	 * In the context of filemap_copy_from_user(), we are not allowed
+	 * to sleep.  We must fail this usercopy attempt and allow
+	 * filemap_copy_from_user() to recover: drop its atomic kmap and use
+	 * a sleeping kmap instead.
+	 */
+	if (in_atomic())
+		return NULL;
+
 	down_read(&mm->mmap_sem);
 	ret = get_user_pages(current, mm, addr, 1, write, 0, &page, NULL);
 	up_read(&mm->mmap_sem);

_