Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Robert Richter and committed by
Ingo Molnar
1ac2e6ca 9985c20f

+48 -74
+3
arch/x86/include/asm/uaccess.h
··· 555 555 556 556 #endif /* CONFIG_X86_WP_WORKS_OK */ 557 557 558 + extern unsigned long 559 + copy_from_user_nmi(void *to, const void __user *from, unsigned long n); 560 + 558 561 /* 559 562 * movsl can be slow when source and dest are not both 8-byte aligned 560 563 */
-35
arch/x86/kernel/cpu/perf_event.c
··· 22 22 #include <linux/sched.h> 23 23 #include <linux/uaccess.h> 24 24 #include <linux/slab.h> 25 - #include <linux/highmem.h> 26 25 #include <linux/cpu.h> 27 26 #include <linux/bitops.h> 28 27 ··· 65 66 66 67 EXTRA_REG_MAX /* number of entries needed */ 67 68 }; 68 - 69 - /* 70 - * best effort, GUP based copy_from_user() that assumes IRQ or NMI context 71 - */ 72 - static unsigned long 73 - copy_from_user_nmi(void *to, const void __user *from, unsigned long n) 74 - { 75 - unsigned long offset, addr = (unsigned long)from; 76 - unsigned long size, len = 0; 77 - struct page *page; 78 - void *map; 79 - int ret; 80 - 81 - do { 82 - ret = __get_user_pages_fast(addr, 1, 0, &page); 83 - if (!ret) 84 - break; 85 - 86 - offset = addr & (PAGE_SIZE - 1); 87 - size = min(PAGE_SIZE - offset, n - len); 88 - 89 - map = kmap_atomic(page); 90 - memcpy(to, map+offset, size); 91 - kunmap_atomic(map); 92 - put_page(page); 93 - 94 - len += size; 95 - to += size; 96 - addr += size; 97 - 98 - } while (len < n); 99 - 100 - return len; 101 - } 102 69 103 70 struct event_constraint { 104 71 union {
+1 -1
arch/x86/lib/Makefile
··· 18 18 19 19 lib-y := delay.o 20 20 lib-y += thunk_$(BITS).o 21 - lib-y += usercopy_$(BITS).o getuser.o putuser.o 21 + lib-y += usercopy_$(BITS).o usercopy.o getuser.o putuser.o 22 22 lib-y += memcpy_$(BITS).o 23 23 lib-$(CONFIG_INSTRUCTION_DECODER) += insn.o inat.o 24 24
+43
arch/x86/lib/usercopy.c
··· 1 + /* 2 + * User address space access functions. 3 + * 4 + * For licencing details see kernel-base/COPYING 5 + */ 6 + 7 + #include <linux/highmem.h> 8 + #include <linux/module.h> 9 + 10 + /* 11 + * best effort, GUP based copy_from_user() that is NMI-safe 12 + */ 13 + unsigned long 14 + copy_from_user_nmi(void *to, const void __user *from, unsigned long n) 15 + { 16 + unsigned long offset, addr = (unsigned long)from; 17 + unsigned long size, len = 0; 18 + struct page *page; 19 + void *map; 20 + int ret; 21 + 22 + do { 23 + ret = __get_user_pages_fast(addr, 1, 0, &page); 24 + if (!ret) 25 + break; 26 + 27 + offset = addr & (PAGE_SIZE - 1); 28 + size = min(PAGE_SIZE - offset, n - len); 29 + 30 + map = kmap_atomic(page); 31 + memcpy(to, map+offset, size); 32 + kunmap_atomic(map); 33 + put_page(page); 34 + 35 + len += size; 36 + to += size; 37 + addr += size; 38 + 39 + } while (len < n); 40 + 41 + return len; 42 + } 43 + EXPORT_SYMBOL_GPL(copy_from_user_nmi);
+1 -38
arch/x86/oprofile/backtrace.c
··· 12 12 #include <linux/sched.h> 13 13 #include <linux/mm.h> 14 14 #include <linux/compat.h> 15 - #include <linux/highmem.h> 15 + #include <linux/uaccess.h> 16 16 17 17 #include <asm/ptrace.h> 18 - #include <asm/uaccess.h> 19 18 #include <asm/stacktrace.h> 20 19 21 20 static int backtrace_stack(void *data, char *name) ··· 36 37 .address = backtrace_address, 37 38 .walk_stack = print_context_stack, 38 39 }; 39 - 40 - /* from arch/x86/kernel/cpu/perf_event.c: */ 41 - 42 - /* 43 - * best effort, GUP based copy_from_user() that assumes IRQ or NMI context 44 - */ 45 - static unsigned long 46 - copy_from_user_nmi(void *to, const void __user *from, unsigned long n) 47 - { 48 - unsigned long offset, addr = (unsigned long)from; 49 - unsigned long size, len = 0; 50 - struct page *page; 51 - void *map; 52 - int ret; 53 - 54 - do { 55 - ret = __get_user_pages_fast(addr, 1, 0, &page); 56 - if (!ret) 57 - break; 58 - 59 - offset = addr & (PAGE_SIZE - 1); 60 - size = min(PAGE_SIZE - offset, n - len); 61 - 62 - map = kmap_atomic(page); 63 - memcpy(to, map+offset, size); 64 - kunmap_atomic(map); 65 - put_page(page); 66 - 67 - len += size; 68 - to += size; 69 - addr += size; 70 - 71 - } while (len < n); 72 - 73 - return len; 74 - } 75 40 76 41 #ifdef CONFIG_COMPAT 77 42 static struct stack_frame_ia32 *