Re: [patch] x86: some lock annotations for user copy paths

Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]
From: Nick Piggin
Date: Wednesday, September 10, 2008 - 7:30 am

On Wed, Sep 10, 2008 at 01:47:55PM +0200, Ingo Molnar wrote:
 
Right, it's a bit of a maze there, but yes we are safe because except for
where I added some missing ones, they all had might_sleep() there too,
which would complain if called under pagefault_disable I think.



That's really the right way to do it, it makes it easier for other archs
to pick up, and it means we can add other things to it easily if needed.

Thanks,
Nick
---

copy_to/from_user and all its variants (except the atomic ones) can take a
page fault and perform non-trivial work like taking mmap_sem and entering
the filesyste/pagecache.

Unfortunately, this often escapes lockdep because a common pattern is to
use it to read in some arguments just set up from userspace, or write data
back to a hot buffer. In those cases, it will be unlikely for page reclaim
to get a window in to cause copy_*_user to fault.

With the new might_lock primitives, add some annotations to x86. I don't
know if I caught all possible faulting points (it's a bit of a maze, and I
didn't really look at 32-bit). But this is a starting point.

Boots and runs OK so far.

Signed-off-by: Nick Piggin <npiggin@suse.de>
---

Index: linux-2.6/include/asm-x86/uaccess_64.h
===================================================================
--- linux-2.6.orig/include/asm-x86/uaccess_64.h
+++ linux-2.6/include/asm-x86/uaccess_64.h
@@ -28,6 +28,8 @@ static __always_inline __must_check
 int __copy_from_user(void *dst, const void __user *src, unsigned size)
 {
 	int ret = 0;
+
+	might_fault();
 	if (!__builtin_constant_p(size))
 		return copy_user_generic(dst, (__force void *)src, size);
 	switch (size) {
@@ -70,6 +72,8 @@ static __always_inline __must_check
 int __copy_to_user(void __user *dst, const void *src, unsigned size)
 {
 	int ret = 0;
+
+	might_fault();
 	if (!__builtin_constant_p(size))
 		return copy_user_generic((__force void *)dst, src, size);
 	switch (size) {
@@ -112,6 +116,8 @@ static __always_inline __must_check
 int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
 {
 	int ret = 0;
+
+	might_fault();
 	if (!__builtin_constant_p(size))
 		return copy_user_generic((__force void *)dst,
 					 (__force void *)src, size);
Index: linux-2.6/include/asm-x86/uaccess.h
===================================================================
--- linux-2.6.orig/include/asm-x86/uaccess.h
+++ linux-2.6/include/asm-x86/uaccess.h
@@ -8,6 +8,8 @@
 #include <linux/thread_info.h>
 #include <linux/prefetch.h>
 #include <linux/string.h>
+#include <linux/lockdep.h>
+#include <linux/sched.h>
 #include <asm/asm.h>
 #include <asm/page.h>
 
@@ -157,6 +159,7 @@ extern int __get_user_bad(void);
 	int __ret_gu;							\
 	unsigned long __val_gu;						\
 	__chk_user_ptr(ptr);						\
+	might_fault();							\
 	switch (sizeof(*(ptr))) {					\
 	case 1:								\
 		__get_user_x(1, __ret_gu, __val_gu, ptr);		\
@@ -241,6 +244,7 @@ extern void __put_user_8(void);
 	int __ret_pu;						\
 	__typeof__(*(ptr)) __pu_val;				\
 	__chk_user_ptr(ptr);					\
+	might_fault();						\
 	__pu_val = x;						\
 	switch (sizeof(*(ptr))) {				\
 	case 1:							\
@@ -265,6 +269,7 @@ extern void __put_user_8(void);
 #define __put_user_size(x, ptr, size, retval, errret)			\
 do {									\
 	retval = 0;							\
+	might_fault();							\
 	__chk_user_ptr(ptr);						\
 	switch (size) {							\
 	case 1:								\
@@ -317,6 +322,7 @@ do {									\
 #define __get_user_size(x, ptr, size, retval, errret)			\
 do {									\
 	retval = 0;							\
+	might_fault();							\
 	__chk_user_ptr(ptr);						\
 	switch (size) {							\
 	case 1:								\
Index: linux-2.6/arch/x86/lib/usercopy_32.c
===================================================================
--- linux-2.6.orig/arch/x86/lib/usercopy_32.c
+++ linux-2.6/arch/x86/lib/usercopy_32.c
@@ -32,7 +32,7 @@ static inline int __movsl_is_ok(unsigned
 #define __do_strncpy_from_user(dst, src, count, res)			   \
 do {									   \
 	int __d0, __d1, __d2;						   \
-	might_sleep();							   \
+	might_fault();							   \
 	__asm__ __volatile__(						   \
 		"	testl %1,%1\n"					   \
 		"	jz 2f\n"					   \
@@ -119,7 +119,7 @@ EXPORT_SYMBOL(strncpy_from_user);
 #define __do_clear_user(addr,size)					\
 do {									\
 	int __d0;							\
-	might_sleep();							\
+	might_fault();							\
 	__asm__ __volatile__(						\
 		"0:	rep; stosl\n"					\
 		"	movl %2,%0\n"					\
@@ -148,7 +148,6 @@ do {									\
 unsigned long
 clear_user(void __user *to, unsigned long n)
 {
-	might_sleep();
 	if (access_ok(VERIFY_WRITE, to, n))
 		__do_clear_user(to, n);
 	return n;
@@ -190,7 +189,7 @@ long strnlen_user(const char __user *s, 
 	unsigned long mask = -__addr_ok(s);
 	unsigned long res, tmp;
 
-	might_sleep();
+	might_fault();
 
 	__asm__ __volatile__(
 		"	testl %0, %0\n"
Index: linux-2.6/arch/x86/lib/usercopy_64.c
===================================================================
--- linux-2.6.orig/arch/x86/lib/usercopy_64.c
+++ linux-2.6/arch/x86/lib/usercopy_64.c
@@ -15,7 +15,7 @@
 #define __do_strncpy_from_user(dst,src,count,res)			   \
 do {									   \
 	long __d0, __d1, __d2;						   \
-	might_sleep();							   \
+	might_fault();							   \
 	__asm__ __volatile__(						   \
 		"	testq %1,%1\n"					   \
 		"	jz 2f\n"					   \
@@ -64,7 +64,7 @@ EXPORT_SYMBOL(strncpy_from_user);
 unsigned long __clear_user(void __user *addr, unsigned long size)
 {
 	long __d0;
-	might_sleep();
+	might_fault();
 	/* no memory constraint because it doesn't change any memory gcc knows
 	   about */
 	asm volatile(
Index: linux-2.6/include/asm-x86/uaccess_32.h
===================================================================
--- linux-2.6.orig/include/asm-x86/uaccess_32.h
+++ linux-2.6/include/asm-x86/uaccess_32.h
@@ -82,8 +82,8 @@ __copy_to_user_inatomic(void __user *to,
 static __always_inline unsigned long __must_check
 __copy_to_user(void __user *to, const void *from, unsigned long n)
 {
-       might_sleep();
-       return __copy_to_user_inatomic(to, from, n);
+	might_fault();
+	return __copy_to_user_inatomic(to, from, n);
 }
 
 static __always_inline unsigned long
@@ -137,7 +137,7 @@ __copy_from_user_inatomic(void *to, cons
 static __always_inline unsigned long
 __copy_from_user(void *to, const void __user *from, unsigned long n)
 {
-	might_sleep();
+	might_fault();
 	if (__builtin_constant_p(n)) {
 		unsigned long ret;
 
@@ -159,7 +159,7 @@ __copy_from_user(void *to, const void __
 static __always_inline unsigned long __copy_from_user_nocache(void *to,
 				const void __user *from, unsigned long n)
 {
-	might_sleep();
+	might_fault();
 	if (__builtin_constant_p(n)) {
 		unsigned long ret;
 
Index: linux-2.6/include/linux/sched.h
===================================================================
--- linux-2.6.orig/include/linux/sched.h
+++ linux-2.6/include/linux/sched.h
@@ -2219,6 +2219,16 @@ static inline void mm_init_owner(struct 
 
 #define TASK_STATE_TO_CHAR_STR "RSDTtZX"
 
+/*
+ * Run some checks for a path that must be able to cope with a page fault.
+ */
+static inline void might_fault(void)
+{
+	might_sleep();
+	if (current->mm)
+		might_lock_read(&current->mm->mmap_sem);
+}
+
 #endif /* __KERNEL__ */
 
 #endif
--
Previous message: [thread] [date] [author]
Next message: [thread] [date] [author]

Messages in current thread:
[patch] x86: some lock annotations for user copy paths, Nick Piggin, (Wed Sep 10, 4:37 am)
Re: [patch] x86: some lock annotations for user copy paths, Peter Zijlstra, (Wed Sep 10, 4:41 am)
Re: [patch] x86: some lock annotations for user copy paths, Nick Piggin, (Wed Sep 10, 7:30 am)
Re: [patch] x86: some lock annotations for user copy paths, Peter Zijlstra, (Wed Sep 10, 8:01 am)
[PATCH] sysfs: fix deadlock, Ingo Molnar, (Fri Sep 12, 2:24 am)
Re: [PATCH] sysfs: fix deadlock, Nick Piggin, (Sun Sep 14, 3:02 pm)
[patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Nick Piggin, (Sun Sep 14, 3:12 pm)
Re: [PATCH] sysfs: fix deadlock, Peter Zijlstra, (Mon Sep 15, 2:15 am)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Andrew Morton, (Wed Sep 17, 1:14 pm)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Matt Mackall, (Wed Sep 17, 1:46 pm)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Jeremy Fitzhardinge, (Thu Sep 18, 12:29 pm)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Matt Mackall, (Thu Sep 18, 2:11 pm)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Hugh Dickins, (Sat Sep 20, 9:12 am)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, David Howells, (Mon Sep 22, 7:54 am)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Nick Piggin, (Mon Sep 22, 10:32 pm)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, David Howells, (Wed Sep 24, 11:18 am)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Matt Mackall, (Wed Sep 24, 11:29 am)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, David Howells, (Wed Sep 24, 11:56 am)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Matt Mackall, (Wed Sep 24, 12:11 pm)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, David Howells, (Wed Sep 24, 12:26 pm)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Hugh Dickins, (Wed Sep 24, 12:29 pm)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Hugh Dickins, (Wed Sep 24, 12:41 pm)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Andrew Morton, (Wed Sep 24, 12:47 pm)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, David Howells, (Wed Sep 24, 12:59 pm)
Re: [patch] mm: tiny-shmem fix lor, mmap_sem vs i_mutex, Hugh Dickins, (Wed Sep 24, 4:43 pm)