aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/lib
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2013-10-24 06:52:06 -0400
committerIngo Molnar <mingo@kernel.org>2013-10-29 07:02:54 -0400
commite00b12e64be9a34ef071de7b6052ca9ea29dd460 (patch)
tree2f3395d06d639550039f3c9aa69c4ad0a4854327 /arch/x86/lib
parent2c42cfbfe10872929c2ba1f8130e31063ff59b94 (diff)
perf/x86: Further optimize copy_from_user_nmi()
Now that we can deal with nested NMI due to IRET re-enabling NMIs and can deal with faults from NMI by making sure we preserve CR2 over NMIs we can in fact simply access user-space memory from NMI context. So rewrite copy_from_user_nmi() to use __copy_from_user_inatomic() and rework the fault path to do the minimal required work before taking the in_atomic() fault handler. In particular avoid perf_sw_event() which would make perf recurse on itself (it should be harmless as our recursion protections should be able to deal with this -- but why tempt fate). Also rename notify_page_fault() to kprobes_fault() as that is a much better name; there is no notifier in it and its specific to kprobes. Don measured that his worst case NMI path shrunk from ~300K cycles to ~150K cycles. Cc: Stephane Eranian <eranian@google.com> Cc: jmario@redhat.com Cc: Arnaldo Carvalho de Melo <acme@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Andi Kleen <ak@linux.intel.com> Cc: dave.hansen@linux.intel.com Tested-by: Don Zickus <dzickus@redhat.com> Signed-off-by: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20131024105206.GM2490@laptop.programming.kicks-ass.net Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/x86/lib')
-rw-r--r--arch/x86/lib/usercopy.c43
1 files changed, 15 insertions, 28 deletions
diff --git a/arch/x86/lib/usercopy.c b/arch/x86/lib/usercopy.c
index 4f74d94c8d97..5465b8613944 100644
--- a/arch/x86/lib/usercopy.c
+++ b/arch/x86/lib/usercopy.c
@@ -11,39 +11,26 @@
11#include <linux/sched.h> 11#include <linux/sched.h>
12 12
13/* 13/*
14 * best effort, GUP based copy_from_user() that is NMI-safe 14 * We rely on the nested NMI work to allow atomic faults from the NMI path; the
15 * nested NMI paths are careful to preserve CR2.
15 */ 16 */
16unsigned long 17unsigned long
17copy_from_user_nmi(void *to, const void __user *from, unsigned long n) 18copy_from_user_nmi(void *to, const void __user *from, unsigned long n)
18{ 19{
19 unsigned long offset, addr = (unsigned long)from; 20 unsigned long ret;
20 unsigned long size, len = 0;
21 struct page *page;
22 void *map;
23 int ret;
24 21
25 if (__range_not_ok(from, n, TASK_SIZE)) 22 if (__range_not_ok(from, n, TASK_SIZE))
26 return len; 23 return 0;
27 24
28 do { 25 /*
29 ret = __get_user_pages_fast(addr, 1, 0, &page); 26 * Even though this function is typically called from NMI/IRQ context
30 if (!ret) 27 * disable pagefaults so that its behaviour is consistent even when
31 break; 28 * called form other contexts.
32 29 */
33 offset = addr & (PAGE_SIZE - 1); 30 pagefault_disable();
34 size = min(PAGE_SIZE - offset, n - len); 31 ret = __copy_from_user_inatomic(to, from, n);
35 32 pagefault_enable();
36 map = kmap_atomic(page); 33
37 memcpy(to, map+offset, size); 34 return n - ret;
38 kunmap_atomic(map);
39 put_page(page);
40
41 len += size;
42 to += size;
43 addr += size;
44
45 } while (len < n);
46
47 return len;
48} 35}
49EXPORT_SYMBOL_GPL(copy_from_user_nmi); 36EXPORT_SYMBOL_GPL(copy_from_user_nmi);