sparc64: Prepare to move to more saner user copy exception handling.
[cascardo/linux.git] / arch / sparc / include / asm / uaccess_64.h
index 37a315d..0244012 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/asi.h>
 #include <asm/spitfire.h>
 #include <asm-generic/uaccess-unaligned.h>
+#include <asm/extable_64.h>
 #endif
 
 #ifndef __ASSEMBLY__
@@ -81,24 +82,6 @@ static inline int access_ok(int type, const void __user * addr, unsigned long si
        return 1;
 }
 
-/*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address at which the program should continue.  No registers are
- * modified, so it is entirely up to the continuation code to figure out
- * what to do.
- *
- * All the routines below use bits of fixup code that are out of line
- * with the main instruction path.  This means when everything is well,
- * we don't even have to jump over them.  Further, they do not intrude
- * on our cache or tlb entries.
- */
-
-struct exception_table_entry {
-        unsigned int insn, fixup;
-};
-
-void __ret_efault(void);
 void __retl_efault(void);
 
 /* Uh, these should become the main single-value transfer routines..
@@ -215,8 +198,11 @@ copy_from_user(void *to, const void __user *from, unsigned long size)
        check_object_size(to, size, false);
 
        ret = ___copy_from_user(to, from, size);
-       if (unlikely(ret))
-               ret = copy_from_user_fixup(to, from, size);
+       if (unlikely(ret)) {
+               if ((long)ret < 0)
+                       ret = copy_from_user_fixup(to, from, size);
+               return ret;
+       }
 
        return ret;
 }
@@ -235,8 +221,11 @@ copy_to_user(void __user *to, const void *from, unsigned long size)
        check_object_size(from, size, true);
 
        ret = ___copy_to_user(to, from, size);
-       if (unlikely(ret))
-               ret = copy_to_user_fixup(to, from, size);
+       if (unlikely(ret)) {
+               if ((long)ret < 0)
+                       ret = copy_to_user_fixup(to, from, size);
+               return ret;
+       }
        return ret;
 }
 #define __copy_to_user copy_to_user
@@ -251,8 +240,11 @@ copy_in_user(void __user *to, void __user *from, unsigned long size)
 {
        unsigned long ret = ___copy_in_user(to, from, size);
 
-       if (unlikely(ret))
-               ret = copy_in_user_fixup(to, from, size);
+       if (unlikely(ret)) {
+               if ((long)ret < 0)
+                       ret = copy_in_user_fixup(to, from, size);
+               return ret;
+       }
        return ret;
 }
 #define __copy_in_user copy_in_user