diff options
author | Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> | 2006-07-01 07:36:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-07-01 12:56:03 -0400 |
commit | 47e5243afe0bd2a1aca1e1f05dfbcc214267fbc9 (patch) | |
tree | 4c71d9b03077f597bc627393ea24099b838a4db9 /arch/um/kernel/skas/uaccess.c | |
parent | 8ec4d41f88872e6a5980558e362c0174dce54e40 (diff) |
[PATCH] uml: make copy_*_user atomic
Make __copy_*_user_inatomic really atomic to avoid "Sleeping function called in
atomic context" warnings, especially from futex code.
This is made by adding another kmap_atomic slot and making copy_*_user_skas
use kmap_atomic; also copy_*_user() becomes atomic, but that's true and is not
a problem for i386 (and we can always add might_sleep there as done
elsewhere). For TT mode kmap is not used, so there's no need for this.
I've had to use another slot since both KM_USER0 and KM_USER1 are used
elsewhere and could cause conflicts. Till now we reused the kmap_atomic slot
list from the subarch, but that's not needed as that list must contain the
common ones (used by generic code) + the ones used in architecture specific
code (and Uml till now used none); so I've taken the i386 one after comparing
it with ones from other archs, and added KM_UML_USERCOPY.
Signed-off-by: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it>
Cc: Jeff Dike <jdike@addtoit.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/um/kernel/skas/uaccess.c')
-rw-r--r-- | arch/um/kernel/skas/uaccess.c | 15 |
1 files changed, 9 insertions, 6 deletions
diff --git a/arch/um/kernel/skas/uaccess.c b/arch/um/kernel/skas/uaccess.c index 5992c3257167..8912cec0fe43 100644 --- a/arch/um/kernel/skas/uaccess.c +++ b/arch/um/kernel/skas/uaccess.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include "linux/kernel.h" | 8 | #include "linux/kernel.h" |
9 | #include "linux/string.h" | 9 | #include "linux/string.h" |
10 | #include "linux/fs.h" | 10 | #include "linux/fs.h" |
11 | #include "linux/hardirq.h" | ||
11 | #include "linux/highmem.h" | 12 | #include "linux/highmem.h" |
12 | #include "asm/page.h" | 13 | #include "asm/page.h" |
13 | #include "asm/pgtable.h" | 14 | #include "asm/pgtable.h" |
@@ -38,7 +39,7 @@ static unsigned long maybe_map(unsigned long virt, int is_write) | |||
38 | return((unsigned long) phys); | 39 | return((unsigned long) phys); |
39 | } | 40 | } |
40 | 41 | ||
41 | static int do_op(unsigned long addr, int len, int is_write, | 42 | static int do_op_one_page(unsigned long addr, int len, int is_write, |
42 | int (*op)(unsigned long addr, int len, void *arg), void *arg) | 43 | int (*op)(unsigned long addr, int len, void *arg), void *arg) |
43 | { | 44 | { |
44 | struct page *page; | 45 | struct page *page; |
@@ -49,9 +50,11 @@ static int do_op(unsigned long addr, int len, int is_write, | |||
49 | return(-1); | 50 | return(-1); |
50 | 51 | ||
51 | page = phys_to_page(addr); | 52 | page = phys_to_page(addr); |
52 | addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK); | 53 | addr = (unsigned long) kmap_atomic(page, KM_UML_USERCOPY) + (addr & ~PAGE_MASK); |
54 | |||
53 | n = (*op)(addr, len, arg); | 55 | n = (*op)(addr, len, arg); |
54 | kunmap(page); | 56 | |
57 | kunmap_atomic(page, KM_UML_USERCOPY); | ||
55 | 58 | ||
56 | return(n); | 59 | return(n); |
57 | } | 60 | } |
@@ -77,7 +80,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) | |||
77 | remain = len; | 80 | remain = len; |
78 | 81 | ||
79 | current->thread.fault_catcher = jmpbuf; | 82 | current->thread.fault_catcher = jmpbuf; |
80 | n = do_op(addr, size, is_write, op, arg); | 83 | n = do_op_one_page(addr, size, is_write, op, arg); |
81 | if(n != 0){ | 84 | if(n != 0){ |
82 | *res = (n < 0 ? remain : 0); | 85 | *res = (n < 0 ? remain : 0); |
83 | goto out; | 86 | goto out; |
@@ -91,7 +94,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) | |||
91 | } | 94 | } |
92 | 95 | ||
93 | while(addr < ((addr + remain) & PAGE_MASK)){ | 96 | while(addr < ((addr + remain) & PAGE_MASK)){ |
94 | n = do_op(addr, PAGE_SIZE, is_write, op, arg); | 97 | n = do_op_one_page(addr, PAGE_SIZE, is_write, op, arg); |
95 | if(n != 0){ | 98 | if(n != 0){ |
96 | *res = (n < 0 ? remain : 0); | 99 | *res = (n < 0 ? remain : 0); |
97 | goto out; | 100 | goto out; |
@@ -105,7 +108,7 @@ static void do_buffer_op(void *jmpbuf, void *arg_ptr) | |||
105 | goto out; | 108 | goto out; |
106 | } | 109 | } |
107 | 110 | ||
108 | n = do_op(addr, remain, is_write, op, arg); | 111 | n = do_op_one_page(addr, remain, is_write, op, arg); |
109 | if(n != 0) | 112 | if(n != 0) |
110 | *res = (n < 0 ? remain : 0); | 113 | *res = (n < 0 ? remain : 0); |
111 | else *res = 0; | 114 | else *res = 0; |