[RFC PATCH 1/9] uaccess: Make copy_from_user_nmi() globally available

Frederic Weisbecker
2010-10-13T05:08:57Z

In order to support user stack dump safely in perf samples from
generic code, export copy_from_user_nmi() from x86 and make it
generally available. For most archs it will map to
copy_from_user_inatomic, but for x86 we need to take care of
not faulting from NMIs.

Since perf is the first user for now, let the overriden x86
implementation in the perf source file.

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Cyrill Gorcunov <gorcunov@openvz.org>
Cc: Tom Zanussi <tzanussi@gmail.com>
Cc: Masami Hiramatsu <mhiramat@redhat.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: Robert Richter <robert.richter@amd.com>
---
arch/x86/include/asm/uaccess.h | 5 +++++
arch/x86/kernel/cpu/perf_event.c | 4 ++--
include/asm-generic/uaccess.h | 4 ++++
3 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index abd3e0e..901daf3 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -229,6 +229,11 @@ extern void __put_user_2(void);
extern void __put_user_4(void);
extern void __put_user_8(void);

+extern unsigned long
+__copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
+
+#define copy_from_user_nmi(to, from, n) __copy_from_user_nmi(to, from, n)
+
#ifdef CONFIG_X86_WP_WORKS_OK

/**
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index e2513f2..d3278da 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -45,8 +45,8 @@ do { \
/*
* best effort, GUP based copy_from_user() that assumes IRQ or NMI context
*/
-static unsigned long
-copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
+unsigned long
+__copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
{
unsigned long offset, addr = (unsigned long)from;
int type = in_nmi() ? KM_NMI : KM_IRQ0;
diff --git a/include/asm-generic/uaccess.h b/include/asm-generic/uaccess.h
index b218b85..a8d5525 100644
--- a/include/asm-generic/uaccess.h
+++ b/include/asm-generic/uaccess.h
@@ -240,6 +240,10 @@ extern int __get_user_bad(void) __attribute__((noreturn));
#define __copy_to_user_inatomic __copy_to_user
#endif

+#ifndef copy_from_user_nmi
+#define copy_from_user_nmi __copy_from_user_inatomic
+#endif
+
static inline long copy_from_user(void *to,
const void __user * from, unsigned long n)
{
--
1.6.2.3