summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2006-05-03 23:02:04 +1000
committerPaul Mackerras <paulus@samba.org>2006-05-03 23:06:46 +1000
commit6bfd93c32a5065d0e858780b3beb0b667081601c (patch)
treeaf13455be2b53f11fbbfec0305731b452db396a2
parent6e1976961c9bd9a3dc368139fab1883961efc879 (diff)
downloadop-kernel-dev-6bfd93c32a5065d0e858780b3beb0b667081601c.zip
op-kernel-dev-6bfd93c32a5065d0e858780b3beb0b667081601c.tar.gz
powerpc: Fix incorrect might_sleep in __get_user/__put_user on kernel addresses
We have a case where __get_user and __put_user can validly be used on kernel addresses in interrupt context - namely, the alignment exception handler, as our get/put_unaligned just do a single access and rely on the alignment exception handler to fix things up in the rare cases where the cpu can't handle it in hardware. Thus we can get alignment exceptions in the network stack at interrupt level. The alignment exception handler does a __get_user to read the instruction and blows up in might_sleep(). Since a __get_user on a kernel address won't actually ever sleep, this makes the might_sleep conditional on the address being less than PAGE_OFFSET. Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--include/asm-powerpc/uaccess.h19
1 files changed, 13 insertions, 6 deletions
diff --git a/include/asm-powerpc/uaccess.h b/include/asm-powerpc/uaccess.h
index 3872e92..d83fc29 100644
--- a/include/asm-powerpc/uaccess.h
+++ b/include/asm-powerpc/uaccess.h
@@ -7,6 +7,7 @@
#include <linux/sched.h>
#include <linux/errno.h>
#include <asm/processor.h>
+#include <asm/page.h>
#define VERIFY_READ 0
#define VERIFY_WRITE 1
@@ -179,9 +180,11 @@ do { \
#define __put_user_nocheck(x, ptr, size) \
({ \
long __pu_err; \
- might_sleep(); \
+ __typeof__(*(ptr)) __user *__pu_addr = (ptr); \
+ if (!is_kernel_addr((unsigned long)__pu_addr)) \
+ might_sleep(); \
__chk_user_ptr(ptr); \
- __put_user_size((x), (ptr), (size), __pu_err); \
+ __put_user_size((x), __pu_addr, (size), __pu_err); \
__pu_err; \
})
@@ -258,9 +261,11 @@ do { \
({ \
long __gu_err; \
unsigned long __gu_val; \
+ const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
__chk_user_ptr(ptr); \
- might_sleep(); \
- __get_user_size(__gu_val, (ptr), (size), __gu_err); \
+ if (!is_kernel_addr((unsigned long)__gu_addr)) \
+ might_sleep(); \
+ __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
(x) = (__typeof__(*(ptr)))__gu_val; \
__gu_err; \
})
@@ -270,9 +275,11 @@ do { \
({ \
long __gu_err; \
long long __gu_val; \
+ const __typeof__(*(ptr)) __user *__gu_addr = (ptr); \
__chk_user_ptr(ptr); \
- might_sleep(); \
- __get_user_size(__gu_val, (ptr), (size), __gu_err); \
+ if (!is_kernel_addr((unsigned long)__gu_addr)) \
+ might_sleep(); \
+ __get_user_size(__gu_val, __gu_addr, (size), __gu_err); \
(x) = (__typeof__(*(ptr)))__gu_val; \
__gu_err; \
})
OpenPOWER on IntegriCloud