* [PATCH] oprofile, x86: Fix nmi-unsafe callgraph support in, 2.6.27 and later
[not found] ` <4DEE2F09.6090803@hotmail.com>
@ 2011-06-07 17:18 ` Robert Richter
2011-06-07 17:24 ` [RFC] [PATCH] x86: Make copy_from_user_nmi() a library function Robert Richter
[not found] ` <4DEFB4DC.7030206@hotmail.com>
0 siblings, 2 replies; 7+ messages in thread
From: Robert Richter @ 2011-06-07 17:18 UTC (permalink / raw)
To: John Lumby
Cc: Maynard Johnson, oprofile list, Ingo Molnar, Peter Zijlstra, LKML
On 07.06.11 10:00:41, John Lumby wrote:
> But please do send your fix along and I'll give it a try. I now have
> capability for capturing un-syslog'd console messages such as these via
> serial console so if it happens again I should be able to provide more
> information.
See the fix below.
-Robert
>From c73bebe2e281ae089499d7cbc3b44a0869c8daf8 Mon Sep 17 00:00:00 2001
From: Robert Richter <robert.richter@amd.com>
Date: Fri, 3 Jun 2011 16:37:47 +0200
Subject: [PATCH] oprofile, x86: Fix nmi-unsafe callgraph support
Current oprofile's x86 callgraph support may trigger page faults
throwing the BUG_ON(in_nmi()) message below. This patch fixes this by
using the same nmi-safe copy-from-user code as in perf.
------------[ cut here ]------------
kernel BUG at .../arch/x86/kernel/traps.c:436!
invalid opcode: 0000 [#1] SMP
last sysfs file: /sys/devices/pci0000:00/0000:00:0a.0/0000:07:00.0/0000:08:04.0/net/eth0/broadcast
CPU 5
Modules linked in:
Pid: 8611, comm: opcontrol Not tainted 2.6.39-00007-gfe47ae7 #1 Advanced Micro Device Anaheim/Anaheim
RIP: 0010:[<ffffffff813e8e35>] [<ffffffff813e8e35>] do_nmi+0x22/0x1ee
RSP: 0000:ffff88042fd47f28 EFLAGS: 00010002
RAX: ffff88042c0a7fd8 RBX: 0000000000000001 RCX: 00000000c0000101
RDX: 00000000ffff8804 RSI: ffffffffffffffff RDI: ffff88042fd47f58
RBP: ffff88042fd47f48 R08: 0000000000000004 R09: 0000000000001484
R10: 0000000000000001 R11: 0000000000000000 R12: ffff88042fd47f58
R13: 0000000000000000 R14: ffff88042fd47d98 R15: 0000000000000020
FS: 00007fca25e56700(0000) GS:ffff88042fd40000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000074 CR3: 000000042d28b000 CR4: 00000000000006e0
DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
Process opcontrol (pid: 8611, threadinfo ffff88042c0a6000, task ffff88042c532310)
Stack:
0000000000000000 0000000000000001 ffff88042c0a7fd8 0000000000000000
ffff88042fd47de8 ffffffff813e897a 0000000000000020 ffff88042fd47d98
0000000000000000 ffff88042c0a7fd8 ffff88042fd47de8 0000000000000074
Call Trace:
<NMI>
[<ffffffff813e897a>] nmi+0x1a/0x20
[<ffffffff813f08ab>] ? bad_to_user+0x25/0x771
<<EOE>>
Code: ff 59 5b 41 5c 41 5d c9 c3 55 65 48 8b 04 25 88 b5 00 00 48 89 e5 41 55 41 54 49 89 fc 53 48 83 ec 08 f6 80 47 e0 ff ff 04 74 04 <0f> 0b eb fe 81 80 44 e0 ff ff 00 00 01 04 65 ff 04 25 c4 0f 01
RIP [<ffffffff813e8e35>] do_nmi+0x22/0x1ee
RSP <ffff88042fd47f28>
---[ end trace ed6752185092104b ]---
Kernel panic - not syncing: Fatal exception in interrupt
Pid: 8611, comm: opcontrol Tainted: G D 2.6.39-00007-gfe47ae7 #1
Call Trace:
<NMI> [<ffffffff813e5e0a>] panic+0x8c/0x188
[<ffffffff813e915c>] oops_end+0x81/0x8e
[<ffffffff8100403d>] die+0x55/0x5e
[<ffffffff813e8c45>] do_trap+0x11c/0x12b
[<ffffffff810023c8>] do_invalid_op+0x91/0x9a
[<ffffffff813e8e35>] ? do_nmi+0x22/0x1ee
[<ffffffff8131e6fa>] ? oprofile_add_sample+0x83/0x95
[<ffffffff81321670>] ? op_amd_check_ctrs+0x4f/0x2cf
[<ffffffff813ee4d5>] invalid_op+0x15/0x20
[<ffffffff813e8e35>] ? do_nmi+0x22/0x1ee
[<ffffffff813e8e7a>] ? do_nmi+0x67/0x1ee
[<ffffffff813e897a>] nmi+0x1a/0x20
[<ffffffff813f08ab>] ? bad_to_user+0x25/0x771
<<EOE>>
Cc: John Lumby <johnlumby@hotmail.com>
Cc: Maynard Johnson <maynardj@us.ibm.com>
Cc: <stable@kernel.org> # .37+
Signed-off-by: Robert Richter <robert.richter@amd.com>
---
arch/x86/oprofile/backtrace.c | 56 ++++++++++++++++++++++++++++++++++------
1 files changed, 47 insertions(+), 9 deletions(-)
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c
index 2d49d4e..88e856e 100644
--- a/arch/x86/oprofile/backtrace.c
+++ b/arch/x86/oprofile/backtrace.c
@@ -11,10 +11,12 @@
#include <linux/oprofile.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/compat.h>
+#include <linux/highmem.h>
+
#include <asm/ptrace.h>
#include <asm/uaccess.h>
#include <asm/stacktrace.h>
-#include <linux/compat.h>
static void backtrace_warning_symbol(void *data, char *msg,
unsigned long symbol)
@@ -49,17 +51,53 @@ static struct stacktrace_ops backtrace_ops = {
.walk_stack = print_context_stack,
};
+/* from arch/x86/kernel/cpu/perf_event.c: */
+
+/*
+ * 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 offset, addr = (unsigned long)from;
+ unsigned long size, len = 0;
+ struct page *page;
+ void *map;
+ int ret;
+
+ do {
+ ret = __get_user_pages_fast(addr, 1, 0, &page);
+ if (!ret)
+ break;
+
+ offset = addr & (PAGE_SIZE - 1);
+ size = min(PAGE_SIZE - offset, n - len);
+
+ map = kmap_atomic(page);
+ memcpy(to, map+offset, size);
+ kunmap_atomic(map);
+ put_page(page);
+
+ len += size;
+ to += size;
+ addr += size;
+
+ } while (len < n);
+
+ return len;
+}
+
#ifdef CONFIG_COMPAT
static struct stack_frame_ia32 *
dump_user_backtrace_32(struct stack_frame_ia32 *head)
{
+ /* Also check accessibility of one struct frame_head beyond: */
struct stack_frame_ia32 bufhead[2];
struct stack_frame_ia32 *fp;
+ unsigned long bytes;
- /* Also check accessibility of one struct frame_head beyond */
- if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
- return NULL;
- if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
+ bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead));
+ if (bytes != sizeof(bufhead))
return NULL;
fp = (struct stack_frame_ia32 *) compat_ptr(bufhead[0].next_frame);
@@ -100,12 +138,12 @@ x86_backtrace_32(struct pt_regs * const regs, unsigned int depth)
static struct stack_frame *dump_user_backtrace(struct stack_frame *head)
{
+ /* Also check accessibility of one struct frame_head beyond: */
struct stack_frame bufhead[2];
+ unsigned long bytes;
- /* Also check accessibility of one struct stack_frame beyond */
- if (!access_ok(VERIFY_READ, head, sizeof(bufhead)))
- return NULL;
- if (__copy_from_user_inatomic(bufhead, head, sizeof(bufhead)))
+ bytes = copy_from_user_nmi(bufhead, head, sizeof(bufhead));
+ if (bytes != sizeof(bufhead))
return NULL;
oprofile_add_trace(bufhead[0].return_address);
--
1.7.5.rc3
--
Advanced Micro Devices, Inc.
Operating System Research Center
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC] [PATCH] x86: Make copy_from_user_nmi() a library function
2011-06-07 17:18 ` [PATCH] oprofile, x86: Fix nmi-unsafe callgraph support in, 2.6.27 and later Robert Richter
@ 2011-06-07 17:24 ` Robert Richter
2011-06-07 20:46 ` Cyrill Gorcunov
` (2 more replies)
[not found] ` <4DEFB4DC.7030206@hotmail.com>
1 sibling, 3 replies; 7+ messages in thread
From: Robert Richter @ 2011-06-07 17:24 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra; +Cc: LKML
On 07.06.11 19:18:22, Robert Richter wrote:
> From c73bebe2e281ae089499d7cbc3b44a0869c8daf8 Mon Sep 17 00:00:00 2001
> From: Robert Richter <robert.richter@amd.com>
> Date: Fri, 3 Jun 2011 16:37:47 +0200
> Subject: [PATCH] oprofile, x86: Fix nmi-unsafe callgraph support
While this patch was a stable fix which introduced duplicate code for
perf and oprofile I suggest merging the code, see the patch below.
-Robert
>From 3652d1b07a0cfce5b26ad186594c1bf8f9ca5898 Mon Sep 17 00:00:00 2001
From: Robert Richter <robert.richter@amd.com>
Date: Tue, 7 Jun 2011 11:49:55 +0200
Subject: [PATCH] x86: Make copy_from_user_nmi() a library function
copy_from_user_nmi() is used in oprofile and perf. Moving it to other
library functions like copy_from_user(). As this is x86 code for 32
and 64 bits, create a new file usercopy.c for unified code.
Signed-off-by: Robert Richter <robert.richter@amd.com>
---
arch/x86/include/asm/uaccess.h | 3 ++
arch/x86/kernel/cpu/perf_event.c | 35 ------------------------------
arch/x86/lib/Makefile | 2 +-
arch/x86/lib/usercopy.c | 43 ++++++++++++++++++++++++++++++++++++++
arch/x86/oprofile/backtrace.c | 39 +---------------------------------
5 files changed, 48 insertions(+), 74 deletions(-)
create mode 100644 arch/x86/lib/usercopy.c
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index abd3e0e..c0236e9 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -556,6 +556,9 @@ struct __large_struct { unsigned long buf[100]; };
#endif /* CONFIG_X86_WP_WORKS_OK */
+extern unsigned long
+copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
+
/*
* movsl can be slow when source and dest are not both 8-byte aligned
*/
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index e638689..46bf36d 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -22,7 +22,6 @@
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
-#include <linux/highmem.h>
#include <linux/cpu.h>
#include <linux/bitops.h>
@@ -43,40 +42,6 @@ do { \
} while (0)
#endif
-/*
- * 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 offset, addr = (unsigned long)from;
- unsigned long size, len = 0;
- struct page *page;
- void *map;
- int ret;
-
- do {
- ret = __get_user_pages_fast(addr, 1, 0, &page);
- if (!ret)
- break;
-
- offset = addr & (PAGE_SIZE - 1);
- size = min(PAGE_SIZE - offset, n - len);
-
- map = kmap_atomic(page);
- memcpy(to, map+offset, size);
- kunmap_atomic(map);
- put_page(page);
-
- len += size;
- to += size;
- addr += size;
-
- } while (len < n);
-
- return len;
-}
-
struct event_constraint {
union {
unsigned long idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index f2479f1..6ba4773 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -18,7 +18,7 @@ obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o
lib-y := delay.o
lib-y += thunk_$(BITS).o
-lib-y += usercopy_$(BITS).o getuser.o putuser.o
+lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
lib-y += memcpy_$(BITS).o
lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c
new file mode 100644
index 0000000..4ef83d3
--- /dev/null
+++ b/arch/x86/lib/usercopy.c
@@ -0,0 +1,43 @@
+/*
+ * User address space access functions.
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+
+#include <linux/highmem.h>
+#include <linux/module.h>
+
+/*
+ * best effort, GUP based copy_from_user() that assumes IRQ or NMI context
+ */
+unsigned long
+copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
+{
+ unsigned long offset, addr = (unsigned long)from;
+ unsigned long size, len = 0;
+ struct page *page;
+ void *map;
+ int ret;
+
+ do {
+ ret = __get_user_pages_fast(addr, 1, 0, &page);
+ if (!ret)
+ break;
+
+ offset = addr & (PAGE_SIZE - 1);
+ size = min(PAGE_SIZE - offset, n - len);
+
+ map = kmap_atomic(page);
+ memcpy(to, map+offset, size);
+ kunmap_atomic(map);
+ put_page(page);
+
+ len += size;
+ to += size;
+ addr += size;
+
+ } while (len < n);
+
+ return len;
+}
+EXPORT_SYMBOL(copy_from_user_nmi);
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c
index 88e856e..087233f 100644
--- a/arch/x86/oprofile/backtrace.c
+++ b/arch/x86/oprofile/backtrace.c
@@ -12,10 +12,9 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/compat.h>
-#include <linux/highmem.h>
+#include <linux/uaccess.h>
#include <asm/ptrace.h>
-#include <asm/uaccess.h>
#include <asm/stacktrace.h>
static void backtrace_warning_symbol(void *data, char *msg,
@@ -51,42 +50,6 @@ static struct stacktrace_ops backtrace_ops = {
.walk_stack = print_context_stack,
};
-/* from arch/x86/kernel/cpu/perf_event.c: */
-
-/*
- * 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 offset, addr = (unsigned long)from;
- unsigned long size, len = 0;
- struct page *page;
- void *map;
- int ret;
-
- do {
- ret = __get_user_pages_fast(addr, 1, 0, &page);
- if (!ret)
- break;
-
- offset = addr & (PAGE_SIZE - 1);
- size = min(PAGE_SIZE - offset, n - len);
-
- map = kmap_atomic(page);
- memcpy(to, map+offset, size);
- kunmap_atomic(map);
- put_page(page);
-
- len += size;
- to += size;
- addr += size;
-
- } while (len < n);
-
- return len;
-}
-
#ifdef CONFIG_COMPAT
static struct stack_frame_ia32 *
dump_user_backtrace_32(struct stack_frame_ia32 *head)
--
1.7.5.rc3
--
Advanced Micro Devices, Inc.
Operating System Research Center
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [RFC] [PATCH] x86: Make copy_from_user_nmi() a library function
2011-06-07 17:24 ` [RFC] [PATCH] x86: Make copy_from_user_nmi() a library function Robert Richter
@ 2011-06-07 20:46 ` Cyrill Gorcunov
2011-07-05 17:22 ` Robert Richter
2011-07-21 19:31 ` [tip:perf/core] x86, perf: " tip-bot for Robert Richter
2 siblings, 0 replies; 7+ messages in thread
From: Cyrill Gorcunov @ 2011-06-07 20:46 UTC (permalink / raw)
To: Robert Richter; +Cc: Ingo Molnar, Peter Zijlstra, LKML
On Tue, Jun 07, 2011 at 07:24:13PM +0200, Robert Richter wrote:
... (unrelated a bit) ...
> +
> + offset = addr & (PAGE_SIZE - 1);
> + size = min(PAGE_SIZE - offset, n - len);
> +
...
Robert, would not offset = addr & ~PAGE_MASK be somehow more
readable? Just a thought.
Cyrill
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] oprofile, x86: Fix nmi-unsafe callgraph support in, 2.6.27 and later
[not found] ` <4DEFB4DC.7030206@hotmail.com>
@ 2011-06-09 12:57 ` Robert Richter
0 siblings, 0 replies; 7+ messages in thread
From: Robert Richter @ 2011-06-09 12:57 UTC (permalink / raw)
To: John Lumby
Cc: Maynard Johnson, oprofile list, Ingo Molnar, Peter Zijlstra, LKML
On 08.06.11 13:43:56, John Lumby wrote:
> I am also a bit confused by the kernel's statement that it's a NULL
> pointer deref. I had previously found that the pointer contains
> 0x0000000a, not NULL. Does the kernel call it NULL for any invalid
> value? Or am I misunderstanding it. Anyway ...
0x0000000a is also considered a NULL pointer access, typically this
happens if a member of a struct which points to NULL is accessed.
>
> Have you or anyone tried this on an intel x86? I'm just curious
> whether it's everyone or only me.
>From your other mail:
"EIP is at print_context_stack=0x45/0xb0
and from a machine-code listing, I found that that offset corresponds
to the line
addr = *stack;
in arch/x86/kernel/dumpstack.c"
Actually this should not happen, because of checking the stack pointer
in valid_stack_ptr(). So could you apply the change below and test if
this throws a bug message?
Thanks,
-Robert
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index e2a3f06..37693f5 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -73,6 +73,8 @@ static inline int valid_stack_ptr(struct thread_info *tinfo,
void *p, unsigned int size, void *end)
{
void *t = tinfo;
+
+ BUG_ON(p < (void *)THREAD_SIZE);
if (end) {
if (p < end && p >= (end-THREAD_SIZE))
return 1;
--
Advanced Micro Devices, Inc.
Operating System Research Center
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [RFC] [PATCH] x86: Make copy_from_user_nmi() a library function
2011-06-07 17:24 ` [RFC] [PATCH] x86: Make copy_from_user_nmi() a library function Robert Richter
2011-06-07 20:46 ` Cyrill Gorcunov
@ 2011-07-05 17:22 ` Robert Richter
2011-07-05 17:40 ` Peter Zijlstra
2011-07-21 19:31 ` [tip:perf/core] x86, perf: " tip-bot for Robert Richter
2 siblings, 1 reply; 7+ messages in thread
From: Robert Richter @ 2011-07-05 17:22 UTC (permalink / raw)
To: Ingo Molnar, Peter Zijlstra; +Cc: LKML
On 07.06.11 19:24:13, Robert Richter wrote:
> On 07.06.11 19:18:22, Robert Richter wrote:
> > From c73bebe2e281ae089499d7cbc3b44a0869c8daf8 Mon Sep 17 00:00:00 2001
> > From: Robert Richter <robert.richter@amd.com>
> > Date: Fri, 3 Jun 2011 16:37:47 +0200
> > Subject: [PATCH] oprofile, x86: Fix nmi-unsafe callgraph support
>
> While this patch was a stable fix which introduced duplicate code for
> perf and oprofile I suggest merging the code, see the patch below.
>
> -Robert
>
>
> From 3652d1b07a0cfce5b26ad186594c1bf8f9ca5898 Mon Sep 17 00:00:00 2001
> From: Robert Richter <robert.richter@amd.com>
> Date: Tue, 7 Jun 2011 11:49:55 +0200
> Subject: [PATCH] x86: Make copy_from_user_nmi() a library function
>
> copy_from_user_nmi() is used in oprofile and perf. Moving it to other
> library functions like copy_from_user(). As this is x86 code for 32
> and 64 bits, create a new file usercopy.c for unified code.
>
> Signed-off-by: Robert Richter <robert.richter@amd.com>
> ---
> arch/x86/include/asm/uaccess.h | 3 ++
> arch/x86/kernel/cpu/perf_event.c | 35 ------------------------------
> arch/x86/lib/Makefile | 2 +-
> arch/x86/lib/usercopy.c | 43 ++++++++++++++++++++++++++++++++++++++
> arch/x86/oprofile/backtrace.c | 39 +---------------------------------
> 5 files changed, 48 insertions(+), 74 deletions(-)
> create mode 100644 arch/x86/lib/usercopy.c
Ingo, Peter,
what about this patch? Any opinion? This one should be against
tip/perf/core now.
Thanks,
-Robert
>
> diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
> index abd3e0e..c0236e9 100644
> --- a/arch/x86/include/asm/uaccess.h
> +++ b/arch/x86/include/asm/uaccess.h
> @@ -556,6 +556,9 @@ struct __large_struct { unsigned long buf[100]; };
>
> #endif /* CONFIG_X86_WP_WORKS_OK */
>
> +extern unsigned long
> +copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
> +
> /*
> * movsl can be slow when source and dest are not both 8-byte aligned
> */
> diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
> index e638689..46bf36d 100644
> --- a/arch/x86/kernel/cpu/perf_event.c
> +++ b/arch/x86/kernel/cpu/perf_event.c
> @@ -22,7 +22,6 @@
> #include <linux/sched.h>
> #include <linux/uaccess.h>
> #include <linux/slab.h>
> -#include <linux/highmem.h>
> #include <linux/cpu.h>
> #include <linux/bitops.h>
>
> @@ -43,40 +42,6 @@ do { \
> } while (0)
> #endif
>
> -/*
> - * 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 offset, addr = (unsigned long)from;
> - unsigned long size, len = 0;
> - struct page *page;
> - void *map;
> - int ret;
> -
> - do {
> - ret = __get_user_pages_fast(addr, 1, 0, &page);
> - if (!ret)
> - break;
> -
> - offset = addr & (PAGE_SIZE - 1);
> - size = min(PAGE_SIZE - offset, n - len);
> -
> - map = kmap_atomic(page);
> - memcpy(to, map+offset, size);
> - kunmap_atomic(map);
> - put_page(page);
> -
> - len += size;
> - to += size;
> - addr += size;
> -
> - } while (len < n);
> -
> - return len;
> -}
> -
> struct event_constraint {
> union {
> unsigned long idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
> diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
> index f2479f1..6ba4773 100644
> --- a/arch/x86/lib/Makefile
> +++ b/arch/x86/lib/Makefile
> @@ -18,7 +18,7 @@ obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o
>
> lib-y := delay.o
> lib-y += thunk_$(BITS).o
> -lib-y += usercopy_$(BITS).o getuser.o putuser.o
> +lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
> lib-y += memcpy_$(BITS).o
> lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
>
> diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c
> new file mode 100644
> index 0000000..4ef83d3
> --- /dev/null
> +++ b/arch/x86/lib/usercopy.c
> @@ -0,0 +1,43 @@
> +/*
> + * User address space access functions.
> + *
> + * For licencing details see kernel-base/COPYING
> + */
> +
> +#include <linux/highmem.h>
> +#include <linux/module.h>
> +
> +/*
> + * best effort, GUP based copy_from_user() that assumes IRQ or NMI context
> + */
> +unsigned long
> +copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
> +{
> + unsigned long offset, addr = (unsigned long)from;
> + unsigned long size, len = 0;
> + struct page *page;
> + void *map;
> + int ret;
> +
> + do {
> + ret = __get_user_pages_fast(addr, 1, 0, &page);
> + if (!ret)
> + break;
> +
> + offset = addr & (PAGE_SIZE - 1);
> + size = min(PAGE_SIZE - offset, n - len);
> +
> + map = kmap_atomic(page);
> + memcpy(to, map+offset, size);
> + kunmap_atomic(map);
> + put_page(page);
> +
> + len += size;
> + to += size;
> + addr += size;
> +
> + } while (len < n);
> +
> + return len;
> +}
> +EXPORT_SYMBOL(copy_from_user_nmi);
> diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c
> index 88e856e..087233f 100644
> --- a/arch/x86/oprofile/backtrace.c
> +++ b/arch/x86/oprofile/backtrace.c
> @@ -12,10 +12,9 @@
> #include <linux/sched.h>
> #include <linux/mm.h>
> #include <linux/compat.h>
> -#include <linux/highmem.h>
> +#include <linux/uaccess.h>
>
> #include <asm/ptrace.h>
> -#include <asm/uaccess.h>
> #include <asm/stacktrace.h>
>
> static void backtrace_warning_symbol(void *data, char *msg,
> @@ -51,42 +50,6 @@ static struct stacktrace_ops backtrace_ops = {
> .walk_stack = print_context_stack,
> };
>
> -/* from arch/x86/kernel/cpu/perf_event.c: */
> -
> -/*
> - * 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 offset, addr = (unsigned long)from;
> - unsigned long size, len = 0;
> - struct page *page;
> - void *map;
> - int ret;
> -
> - do {
> - ret = __get_user_pages_fast(addr, 1, 0, &page);
> - if (!ret)
> - break;
> -
> - offset = addr & (PAGE_SIZE - 1);
> - size = min(PAGE_SIZE - offset, n - len);
> -
> - map = kmap_atomic(page);
> - memcpy(to, map+offset, size);
> - kunmap_atomic(map);
> - put_page(page);
> -
> - len += size;
> - to += size;
> - addr += size;
> -
> - } while (len < n);
> -
> - return len;
> -}
> -
> #ifdef CONFIG_COMPAT
> static struct stack_frame_ia32 *
> dump_user_backtrace_32(struct stack_frame_ia32 *head)
> --
> 1.7.5.rc3
>
>
>
> --
> Advanced Micro Devices, Inc.
> Operating System Research Center
--
Advanced Micro Devices, Inc.
Operating System Research Center
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC] [PATCH] x86: Make copy_from_user_nmi() a library function
2011-07-05 17:22 ` Robert Richter
@ 2011-07-05 17:40 ` Peter Zijlstra
0 siblings, 0 replies; 7+ messages in thread
From: Peter Zijlstra @ 2011-07-05 17:40 UTC (permalink / raw)
To: Robert Richter; +Cc: Ingo Molnar, LKML
On Tue, 2011-07-05 at 19:22 +0200, Robert Richter wrote:
> Ingo, Peter,
>
> what about this patch? Any opinion? This one should be against
> tip/perf/core now.
Ah, thanks for the reminder, yeah, took it with EXPORT_SYMBOL_GPL.
---
Subject: x86: Make copy_from_user_nmi() a library function
From: Robert Richter <robert.richter@amd.com>
Date: Tue, 7 Jun 2011 11:49:55 +0200
copy_from_user_nmi() is used in oprofile and perf. Moving it to other
library functions like copy_from_user(). As this is x86 code for 32
and 64 bits, create a new file usercopy.c for unified code.
Signed-off-by: Robert Richter <robert.richter@amd.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20110607172413.GJ20052@erda.amd.com
---
arch/x86/include/asm/uaccess.h | 3 ++
arch/x86/kernel/cpu/perf_event.c | 35 -------------------------------
arch/x86/lib/Makefile | 2 -
arch/x86/lib/usercopy.c | 43 +++++++++++++++++++++++++++++++++++++++
arch/x86/oprofile/backtrace.c | 39 -----------------------------------
5 files changed, 48 insertions(+), 74 deletions(-)
create mode 100644 arch/x86/lib/usercopy.c
Index: linux-2.6/arch/x86/include/asm/uaccess.h
===================================================================
--- linux-2.6.orig/arch/x86/include/asm/uaccess.h
+++ linux-2.6/arch/x86/include/asm/uaccess.h
@@ -555,6 +555,9 @@ struct __large_struct { unsigned long bu
#endif /* CONFIG_X86_WP_WORKS_OK */
+extern unsigned long
+copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
+
/*
* movsl can be slow when source and dest are not both 8-byte aligned
*/
Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c
===================================================================
--- linux-2.6.orig/arch/x86/kernel/cpu/perf_event.c
+++ linux-2.6/arch/x86/kernel/cpu/perf_event.c
@@ -22,7 +22,6 @@
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
-#include <linux/highmem.h>
#include <linux/cpu.h>
#include <linux/bitops.h>
@@ -67,40 +66,6 @@ enum extra_reg_type {
EXTRA_REG_MAX /* number of entries needed */
};
-/*
- * 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 offset, addr = (unsigned long)from;
- unsigned long size, len = 0;
- struct page *page;
- void *map;
- int ret;
-
- do {
- ret = __get_user_pages_fast(addr, 1, 0, &page);
- if (!ret)
- break;
-
- offset = addr & (PAGE_SIZE - 1);
- size = min(PAGE_SIZE - offset, n - len);
-
- map = kmap_atomic(page);
- memcpy(to, map+offset, size);
- kunmap_atomic(map);
- put_page(page);
-
- len += size;
- to += size;
- addr += size;
-
- } while (len < n);
-
- return len;
-}
-
struct event_constraint {
union {
unsigned long idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
Index: linux-2.6/arch/x86/lib/Makefile
===================================================================
--- linux-2.6.orig/arch/x86/lib/Makefile
+++ linux-2.6/arch/x86/lib/Makefile
@@ -18,7 +18,7 @@ obj-$(CONFIG_SMP) += msr-smp.o cache-smp
lib-y := delay.o
lib-y += thunk_$(BITS).o
-lib-y += usercopy_$(BITS).o getuser.o putuser.o
+lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
lib-y += memcpy_$(BITS).o
lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
Index: linux-2.6/arch/x86/lib/usercopy.c
===================================================================
--- /dev/null
+++ linux-2.6/arch/x86/lib/usercopy.c
@@ -0,0 +1,43 @@
+/*
+ * User address space access functions.
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+
+#include <linux/highmem.h>
+#include <linux/module.h>
+
+/*
+ * best effort, GUP based copy_from_user() that is NMI-safe
+ */
+unsigned long
+copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
+{
+ unsigned long offset, addr = (unsigned long)from;
+ unsigned long size, len = 0;
+ struct page *page;
+ void *map;
+ int ret;
+
+ do {
+ ret = __get_user_pages_fast(addr, 1, 0, &page);
+ if (!ret)
+ break;
+
+ offset = addr & (PAGE_SIZE - 1);
+ size = min(PAGE_SIZE - offset, n - len);
+
+ map = kmap_atomic(page);
+ memcpy(to, map+offset, size);
+ kunmap_atomic(map);
+ put_page(page);
+
+ len += size;
+ to += size;
+ addr += size;
+
+ } while (len < n);
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(copy_from_user_nmi);
Index: linux-2.6/arch/x86/oprofile/backtrace.c
===================================================================
--- linux-2.6.orig/arch/x86/oprofile/backtrace.c
+++ linux-2.6/arch/x86/oprofile/backtrace.c
@@ -12,10 +12,9 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/compat.h>
-#include <linux/highmem.h>
+#include <linux/uaccess.h>
#include <asm/ptrace.h>
-#include <asm/uaccess.h>
#include <asm/stacktrace.h>
static int backtrace_stack(void *data, char *name)
@@ -38,42 +37,6 @@ static struct stacktrace_ops backtrace_o
.walk_stack = print_context_stack,
};
-/* from arch/x86/kernel/cpu/perf_event.c: */
-
-/*
- * 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 offset, addr = (unsigned long)from;
- unsigned long size, len = 0;
- struct page *page;
- void *map;
- int ret;
-
- do {
- ret = __get_user_pages_fast(addr, 1, 0, &page);
- if (!ret)
- break;
-
- offset = addr & (PAGE_SIZE - 1);
- size = min(PAGE_SIZE - offset, n - len);
-
- map = kmap_atomic(page);
- memcpy(to, map+offset, size);
- kunmap_atomic(map);
- put_page(page);
-
- len += size;
- to += size;
- addr += size;
-
- } while (len < n);
-
- return len;
-}
-
#ifdef CONFIG_COMPAT
static struct stack_frame_ia32 *
dump_user_backtrace_32(struct stack_frame_ia32 *head)
^ permalink raw reply [flat|nested] 7+ messages in thread
* [tip:perf/core] x86, perf: Make copy_from_user_nmi() a library function
2011-06-07 17:24 ` [RFC] [PATCH] x86: Make copy_from_user_nmi() a library function Robert Richter
2011-06-07 20:46 ` Cyrill Gorcunov
2011-07-05 17:22 ` Robert Richter
@ 2011-07-21 19:31 ` tip-bot for Robert Richter
2 siblings, 0 replies; 7+ messages in thread
From: tip-bot for Robert Richter @ 2011-07-21 19:31 UTC (permalink / raw)
To: linux-tip-commits
Cc: linux-kernel, hpa, mingo, robert.richter, a.p.zijlstra, tglx,
mingo
Commit-ID: 1ac2e6ca44e13a087eb7438d284f887097ee7e84
Gitweb: http://git.kernel.org/tip/1ac2e6ca44e13a087eb7438d284f887097ee7e84
Author: Robert Richter <robert.richter@amd.com>
AuthorDate: Tue, 7 Jun 2011 11:49:55 +0200
Committer: Ingo Molnar <mingo@elte.hu>
CommitDate: Thu, 21 Jul 2011 20:41:57 +0200
x86, perf: Make copy_from_user_nmi() a library function
copy_from_user_nmi() is used in oprofile and perf. Moving it to other
library functions like copy_from_user(). As this is x86 code for 32
and 64 bits, create a new file usercopy.c for unified code.
Signed-off-by: Robert Richter <robert.richter@amd.com>
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20110607172413.GJ20052@erda.amd.com
Signed-off-by: Ingo Molnar <mingo@elte.hu>
---
arch/x86/include/asm/uaccess.h | 3 ++
arch/x86/kernel/cpu/perf_event.c | 35 ------------------------------
arch/x86/lib/Makefile | 2 +-
arch/x86/lib/usercopy.c | 43 ++++++++++++++++++++++++++++++++++++++
arch/x86/oprofile/backtrace.c | 39 +---------------------------------
5 files changed, 48 insertions(+), 74 deletions(-)
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 99ddd14..36361bf 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
@@ -555,6 +555,9 @@ struct __large_struct { unsigned long buf[100]; };
#endif /* CONFIG_X86_WP_WORKS_OK */
+extern unsigned long
+copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
+
/*
* movsl can be slow when source and dest are not both 8-byte aligned
*/
diff --git a/arch/x86/kernel/cpu/perf_event.c b/arch/x86/kernel/cpu/perf_event.c
index b7a010f..4ee3abf 100644
--- a/arch/x86/kernel/cpu/perf_event.c
+++ b/arch/x86/kernel/cpu/perf_event.c
@@ -22,7 +22,6 @@
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
-#include <linux/highmem.h>
#include <linux/cpu.h>
#include <linux/bitops.h>
@@ -67,40 +66,6 @@ enum extra_reg_type {
EXTRA_REG_MAX /* number of entries needed */
};
-/*
- * 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 offset, addr = (unsigned long)from;
- unsigned long size, len = 0;
- struct page *page;
- void *map;
- int ret;
-
- do {
- ret = __get_user_pages_fast(addr, 1, 0, &page);
- if (!ret)
- break;
-
- offset = addr & (PAGE_SIZE - 1);
- size = min(PAGE_SIZE - offset, n - len);
-
- map = kmap_atomic(page);
- memcpy(to, map+offset, size);
- kunmap_atomic(map);
- put_page(page);
-
- len += size;
- to += size;
- addr += size;
-
- } while (len < n);
-
- return len;
-}
-
struct event_constraint {
union {
unsigned long idxmsk[BITS_TO_LONGS(X86_PMC_IDX_MAX)];
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile
index f2479f1..6ba4773 100644
--- a/arch/x86/lib/Makefile
+++ b/arch/x86/lib/Makefile
@@ -18,7 +18,7 @@ obj-$(CONFIG_SMP) += msr-smp.o cache-smp.o
lib-y := delay.o
lib-y += thunk_$(BITS).o
-lib-y += usercopy_$(BITS).o getuser.o putuser.o
+lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o
lib-y += memcpy_$(BITS).o
lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o
diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c
new file mode 100644
index 0000000..97be9cb
--- /dev/null
+++ b/arch/x86/lib/usercopy.c
@@ -0,0 +1,43 @@
+/*
+ * User address space access functions.
+ *
+ * For licencing details see kernel-base/COPYING
+ */
+
+#include <linux/highmem.h>
+#include <linux/module.h>
+
+/*
+ * best effort, GUP based copy_from_user() that is NMI-safe
+ */
+unsigned long
+copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
+{
+ unsigned long offset, addr = (unsigned long)from;
+ unsigned long size, len = 0;
+ struct page *page;
+ void *map;
+ int ret;
+
+ do {
+ ret = __get_user_pages_fast(addr, 1, 0, &page);
+ if (!ret)
+ break;
+
+ offset = addr & (PAGE_SIZE - 1);
+ size = min(PAGE_SIZE - offset, n - len);
+
+ map = kmap_atomic(page);
+ memcpy(to, map+offset, size);
+ kunmap_atomic(map);
+ put_page(page);
+
+ len += size;
+ to += size;
+ addr += size;
+
+ } while (len < n);
+
+ return len;
+}
+EXPORT_SYMBOL_GPL(copy_from_user_nmi);
diff --git a/arch/x86/oprofile/backtrace.c b/arch/x86/oprofile/backtrace.c
index 32f78eb..bff89df 100644
--- a/arch/x86/oprofile/backtrace.c
+++ b/arch/x86/oprofile/backtrace.c
@@ -12,10 +12,9 @@
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/compat.h>
-#include <linux/highmem.h>
+#include <linux/uaccess.h>
#include <asm/ptrace.h>
-#include <asm/uaccess.h>
#include <asm/stacktrace.h>
static int backtrace_stack(void *data, char *name)
@@ -38,42 +37,6 @@ static struct stacktrace_ops backtrace_ops = {
.walk_stack = print_context_stack,
};
-/* from arch/x86/kernel/cpu/perf_event.c: */
-
-/*
- * 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 offset, addr = (unsigned long)from;
- unsigned long size, len = 0;
- struct page *page;
- void *map;
- int ret;
-
- do {
- ret = __get_user_pages_fast(addr, 1, 0, &page);
- if (!ret)
- break;
-
- offset = addr & (PAGE_SIZE - 1);
- size = min(PAGE_SIZE - offset, n - len);
-
- map = kmap_atomic(page);
- memcpy(to, map+offset, size);
- kunmap_atomic(map);
- put_page(page);
-
- len += size;
- to += size;
- addr += size;
-
- } while (len < n);
-
- return len;
-}
-
#ifdef CONFIG_COMPAT
static struct stack_frame_ia32 *
dump_user_backtrace_32(struct stack_frame_ia32 *head)
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2011-07-21 19:32 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <COL116-W380DF5357514E3CC28BB66A38F0@phx.gbl>
[not found] ` <4DD5046F.3000807@us.ibm.com>
[not found] ` <4DD53BC8.2010208@hotmail.com>
[not found] ` <20110607105259.GE20052@erda.amd.com>
[not found] ` <4DEE2F09.6090803@hotmail.com>
2011-06-07 17:18 ` [PATCH] oprofile, x86: Fix nmi-unsafe callgraph support in, 2.6.27 and later Robert Richter
2011-06-07 17:24 ` [RFC] [PATCH] x86: Make copy_from_user_nmi() a library function Robert Richter
2011-06-07 20:46 ` Cyrill Gorcunov
2011-07-05 17:22 ` Robert Richter
2011-07-05 17:40 ` Peter Zijlstra
2011-07-21 19:31 ` [tip:perf/core] x86, perf: " tip-bot for Robert Richter
[not found] ` <4DEFB4DC.7030206@hotmail.com>
2011-06-09 12:57 ` [PATCH] oprofile, x86: Fix nmi-unsafe callgraph support in, 2.6.27 and later Robert Richter
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.