aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/lib/user_fixup.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2005-09-29 00:06:47 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-09-29 00:06:47 -0400
commitefdc1e2083e04cc70721d55803889b346c1a3de2 (patch)
tree9f24fab33f795a69bb2dc43a8f3613392762ff02 /arch/sparc64/lib/user_fixup.c
parent5fd29752f09cabff582f65c0ce35518db4c64937 (diff)
[SPARC64]: Simplify user fault fixup handling.
Instead of doing byte-at-a-time user accesses to figure out where the fault occurred, read the saved fault_address from the current thread structure. For the sake of defensive programming, if the fault_address does not fall into the user buffer range, simply assume the whole area faulted. This will cause the fixup for copy_from_user() to clear the entire kernel side buffer. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'arch/sparc64/lib/user_fixup.c')
-rw-r--r--arch/sparc64/lib/user_fixup.c63
1 files changed, 29 insertions, 34 deletions
diff --git a/arch/sparc64/lib/user_fixup.c b/arch/sparc64/lib/user_fixup.c
index 0278e34125db..19d1fdb17d0e 100644
--- a/arch/sparc64/lib/user_fixup.c
+++ b/arch/sparc64/lib/user_fixup.c
@@ -11,61 +11,56 @@
11 11
12/* Calculating the exact fault address when using 12/* Calculating the exact fault address when using
13 * block loads and stores can be very complicated. 13 * block loads and stores can be very complicated.
14 *
14 * Instead of trying to be clever and handling all 15 * Instead of trying to be clever and handling all
15 * of the cases, just fix things up simply here. 16 * of the cases, just fix things up simply here.
16 */ 17 */
17 18
18unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size) 19static unsigned long compute_size(unsigned long start, unsigned long size, unsigned long *offset)
19{ 20{
20 char *dst = to; 21 unsigned long fault_addr = current_thread_info()->fault_address;
21 const char __user *src = from; 22 unsigned long end = start + size;
22 23
23 while (size) { 24 if (fault_addr < start || fault_addr >= end) {
24 if (__get_user(*dst, src)) 25 *offset = 0;
25 break; 26 } else {
26 dst++; 27 *offset = start - fault_addr;
27 src++; 28 size = end - fault_addr;
28 size--;
29 } 29 }
30 return size;
31}
30 32
31 if (size) 33unsigned long copy_from_user_fixup(void *to, const void __user *from, unsigned long size)
32 memset(dst, 0, size); 34{
35 unsigned long offset;
36
37 size = compute_size((unsigned long) from, size, &offset);
38 if (likely(size))
39 memset(to + offset, 0, size);
33 40
34 return size; 41 return size;
35} 42}
36 43
37unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size) 44unsigned long copy_to_user_fixup(void __user *to, const void *from, unsigned long size)
38{ 45{
39 char __user *dst = to; 46 unsigned long offset;
40 const char *src = from;
41
42 while (size) {
43 if (__put_user(*src, dst))
44 break;
45 dst++;
46 src++;
47 size--;
48 }
49 47
50 return size; 48 return compute_size((unsigned long) to, size, &offset);
51} 49}
52 50
53unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size) 51unsigned long copy_in_user_fixup(void __user *to, void __user *from, unsigned long size)
54{ 52{
55 char __user *dst = to; 53 unsigned long fault_addr = current_thread_info()->fault_address;
56 char __user *src = from; 54 unsigned long start = (unsigned long) to;
55 unsigned long end = start + size;
57 56
58 while (size) { 57 if (fault_addr >= start && fault_addr < end)
59 char tmp; 58 return end - fault_addr;
60 59
61 if (__get_user(tmp, src)) 60 start = (unsigned long) from;
62 break; 61 end = start + size;
63 if (__put_user(tmp, dst)) 62 if (fault_addr >= start && fault_addr < end)
64 break; 63 return end - fault_addr;
65 dst++;
66 src++;
67 size--;
68 }
69 64
70 return size; 65 return size;
71} 66}