* [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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ 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; 8+ 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] 8+ messages in thread
* Re: [PATCH] oprofile, x86: Fix nmi-unsafe callgraph support in, 2.6.27 and later
@ 2011-06-13 13:40 John Lumby
0 siblings, 0 replies; 8+ messages in thread
From: John Lumby @ 2011-06-13 13:40 UTC (permalink / raw)
To: Robert Richter
Cc: Maynard Johnson, oprofile list, mingo, peterz, linux-kernel list
On 06/09/11 08:57, Robert Richter wrote:
> On 08.06.11 13:43:56, John Lumby wrote:
>
> "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?
I applied that change and, yes, it throws the BUG :
kernel BUG at arch/x86/kernel/dumpstack.c : 76!
It appears that the existing test in valid_stack_ptr makes too many assumptions
about the other variables involved to catch all cases.
Also, changing that test by adding a simplistic check for an absolute
range is not sufficient, as another crash then occurs in dump_trace at
the line
stack = (unsigned long *)context->previous_esp;
This patch to dumpstack_32.c seems to work for my system:
(although it is probably more of a cover-up than a fix)
--- linux-2.6.39-FLG/arch/x86/kernel/dumpstack_32.c.orig 2011-05-19
00:06:34.000000000 -0400
+++ linux-2.6.39-FLG/arch/x86/kernel/dumpstack_32.c 2011-06-12
23:09:16.000000000 -0400
@@ -42,6 +42,19 @@ void dump_trace(struct task_struct *task
context = (struct thread_info *)
((unsigned long)stack & (~(THREAD_SIZE - 1)));
+
+ /* crude bugcheck */
+ if ( ((unsigned long)stack <= 1024)
+ || ((unsigned long)stack >= 0xffffe000)
+ || ((unsigned long)context <= 1024)
+ || ((unsigned long)context >= 0xffffe000)
+ ) {
+#ifdef NOISY_DUMP_TRACE
+ printk("dump_trace: pid %d stack= %p context= %p\n"
+ ,(task ? task->pid : -1),stack,context);
+#endif /* NOISY_DUMP_TRACE */
+ break;
+ }
bp = ops->walk_stack(context, stack, bp, ops, data, NULL, &graph);
stack = (unsigned long *)context->previous_esp;
> 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;
>
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2011-07-21 19:32 UTC | newest]
Thread overview: 8+ 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
2011-06-13 13:40 John Lumby
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).