diff options
| -rw-r--r-- | arch/x86/kernel/ftrace.c | 8 | ||||
| -rw-r--r-- | arch/x86/mm/testmmiotrace.c | 29 | ||||
| -rw-r--r-- | include/linux/smp_lock.h | 21 | ||||
| -rw-r--r-- | include/trace/events/bkl.h | 61 | ||||
| -rw-r--r-- | kernel/trace/ftrace.c | 68 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 36 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 23 | ||||
| -rw-r--r-- | kernel/trace/trace_events_filter.c | 155 | ||||
| -rw-r--r-- | lib/kernel_lock.c | 20 |
9 files changed, 295 insertions, 126 deletions
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c index 9dbb527e1652..25e6f5fc4b1e 100644 --- a/arch/x86/kernel/ftrace.c +++ b/arch/x86/kernel/ftrace.c | |||
| @@ -9,6 +9,8 @@ | |||
| 9 | * the dangers of modifying code on the run. | 9 | * the dangers of modifying code on the run. |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 13 | |||
| 12 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
| 13 | #include <linux/hardirq.h> | 15 | #include <linux/hardirq.h> |
| 14 | #include <linux/uaccess.h> | 16 | #include <linux/uaccess.h> |
| @@ -336,15 +338,15 @@ int __init ftrace_dyn_arch_init(void *data) | |||
| 336 | 338 | ||
| 337 | switch (faulted) { | 339 | switch (faulted) { |
| 338 | case 0: | 340 | case 0: |
| 339 | pr_info("ftrace: converting mcount calls to 0f 1f 44 00 00\n"); | 341 | pr_info("converting mcount calls to 0f 1f 44 00 00\n"); |
| 340 | memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE); | 342 | memcpy(ftrace_nop, ftrace_test_p6nop, MCOUNT_INSN_SIZE); |
| 341 | break; | 343 | break; |
| 342 | case 1: | 344 | case 1: |
| 343 | pr_info("ftrace: converting mcount calls to 66 66 66 66 90\n"); | 345 | pr_info("converting mcount calls to 66 66 66 66 90\n"); |
| 344 | memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE); | 346 | memcpy(ftrace_nop, ftrace_test_nop5, MCOUNT_INSN_SIZE); |
| 345 | break; | 347 | break; |
| 346 | case 2: | 348 | case 2: |
| 347 | pr_info("ftrace: converting mcount calls to jmp . + 5\n"); | 349 | pr_info("converting mcount calls to jmp . + 5\n"); |
| 348 | memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE); | 350 | memcpy(ftrace_nop, ftrace_test_jmp, MCOUNT_INSN_SIZE); |
| 349 | break; | 351 | break; |
| 350 | } | 352 | } |
diff --git a/arch/x86/mm/testmmiotrace.c b/arch/x86/mm/testmmiotrace.c index 427fd1b56df5..8565d944f7cf 100644 --- a/arch/x86/mm/testmmiotrace.c +++ b/arch/x86/mm/testmmiotrace.c | |||
| @@ -1,12 +1,13 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * Written by Pekka Paalanen, 2008-2009 <pq@iki.fi> | 2 | * Written by Pekka Paalanen, 2008-2009 <pq@iki.fi> |
| 3 | */ | 3 | */ |
| 4 | |||
| 5 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
| 6 | |||
| 4 | #include <linux/module.h> | 7 | #include <linux/module.h> |
| 5 | #include <linux/io.h> | 8 | #include <linux/io.h> |
| 6 | #include <linux/mmiotrace.h> | 9 | #include <linux/mmiotrace.h> |
| 7 | 10 | ||
| 8 | #define MODULE_NAME "testmmiotrace" | ||
| 9 | |||
| 10 | static unsigned long mmio_address; | 11 | static unsigned long mmio_address; |
| 11 | module_param(mmio_address, ulong, 0); | 12 | module_param(mmio_address, ulong, 0); |
| 12 | MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB " | 13 | MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB " |
| @@ -30,7 +31,7 @@ static unsigned v32(unsigned i) | |||
| 30 | static void do_write_test(void __iomem *p) | 31 | static void do_write_test(void __iomem *p) |
| 31 | { | 32 | { |
| 32 | unsigned int i; | 33 | unsigned int i; |
| 33 | pr_info(MODULE_NAME ": write test.\n"); | 34 | pr_info("write test.\n"); |
| 34 | mmiotrace_printk("Write test.\n"); | 35 | mmiotrace_printk("Write test.\n"); |
| 35 | 36 | ||
| 36 | for (i = 0; i < 256; i++) | 37 | for (i = 0; i < 256; i++) |
| @@ -47,7 +48,7 @@ static void do_read_test(void __iomem *p) | |||
| 47 | { | 48 | { |
| 48 | unsigned int i; | 49 | unsigned int i; |
| 49 | unsigned errs[3] = { 0 }; | 50 | unsigned errs[3] = { 0 }; |
| 50 | pr_info(MODULE_NAME ": read test.\n"); | 51 | pr_info("read test.\n"); |
| 51 | mmiotrace_printk("Read test.\n"); | 52 | mmiotrace_printk("Read test.\n"); |
| 52 | 53 | ||
| 53 | for (i = 0; i < 256; i++) | 54 | for (i = 0; i < 256; i++) |
| @@ -68,7 +69,7 @@ static void do_read_test(void __iomem *p) | |||
| 68 | 69 | ||
| 69 | static void do_read_far_test(void __iomem *p) | 70 | static void do_read_far_test(void __iomem *p) |
| 70 | { | 71 | { |
| 71 | pr_info(MODULE_NAME ": read far test.\n"); | 72 | pr_info("read far test.\n"); |
| 72 | mmiotrace_printk("Read far test.\n"); | 73 | mmiotrace_printk("Read far test.\n"); |
| 73 | 74 | ||
| 74 | ioread32(p + read_far); | 75 | ioread32(p + read_far); |
| @@ -78,7 +79,7 @@ static void do_test(unsigned long size) | |||
| 78 | { | 79 | { |
| 79 | void __iomem *p = ioremap_nocache(mmio_address, size); | 80 | void __iomem *p = ioremap_nocache(mmio_address, size); |
| 80 | if (!p) { | 81 | if (!p) { |
| 81 | pr_err(MODULE_NAME ": could not ioremap, aborting.\n"); | 82 | pr_err("could not ioremap, aborting.\n"); |
| 82 | return; | 83 | return; |
| 83 | } | 84 | } |
| 84 | mmiotrace_printk("ioremap returned %p.\n", p); | 85 | mmiotrace_printk("ioremap returned %p.\n", p); |
| @@ -94,24 +95,22 @@ static int __init init(void) | |||
| 94 | unsigned long size = (read_far) ? (8 << 20) : (16 << 10); | 95 | unsigned long size = (read_far) ? (8 << 20) : (16 << 10); |
| 95 | 96 | ||
| 96 | if (mmio_address == 0) { | 97 | if (mmio_address == 0) { |
| 97 | pr_err(MODULE_NAME ": you have to use the module argument " | 98 | pr_err("you have to use the module argument mmio_address.\n"); |
| 98 | "mmio_address.\n"); | 99 | pr_err("DO NOT LOAD THIS MODULE UNLESS YOU REALLY KNOW WHAT YOU ARE DOING!\n"); |
| 99 | pr_err(MODULE_NAME ": DO NOT LOAD THIS MODULE UNLESS" | ||
| 100 | " YOU REALLY KNOW WHAT YOU ARE DOING!\n"); | ||
| 101 | return -ENXIO; | 100 | return -ENXIO; |
| 102 | } | 101 | } |
| 103 | 102 | ||
| 104 | pr_warning(MODULE_NAME ": WARNING: mapping %lu kB @ 0x%08lx in PCI " | 103 | pr_warning("WARNING: mapping %lu kB @ 0x%08lx in PCI address space, " |
| 105 | "address space, and writing 16 kB of rubbish in there.\n", | 104 | "and writing 16 kB of rubbish in there.\n", |
| 106 | size >> 10, mmio_address); | 105 | size >> 10, mmio_address); |
| 107 | do_test(size); | 106 | do_test(size); |
| 108 | pr_info(MODULE_NAME ": All done.\n"); | 107 | pr_info("All done.\n"); |
| 109 | return 0; | 108 | return 0; |
| 110 | } | 109 | } |
| 111 | 110 | ||
| 112 | static void __exit cleanup(void) | 111 | static void __exit cleanup(void) |
| 113 | { | 112 | { |
| 114 | pr_debug(MODULE_NAME ": unloaded.\n"); | 113 | pr_debug("unloaded.\n"); |
| 115 | } | 114 | } |
| 116 | 115 | ||
| 117 | module_init(init); | 116 | module_init(init); |
diff --git a/include/linux/smp_lock.h b/include/linux/smp_lock.h index 813be59bf345..2ea1dd1ba21c 100644 --- a/include/linux/smp_lock.h +++ b/include/linux/smp_lock.h | |||
| @@ -24,8 +24,21 @@ static inline int reacquire_kernel_lock(struct task_struct *task) | |||
| 24 | return 0; | 24 | return 0; |
| 25 | } | 25 | } |
| 26 | 26 | ||
| 27 | extern void __lockfunc lock_kernel(void) __acquires(kernel_lock); | 27 | extern void __lockfunc |
| 28 | extern void __lockfunc unlock_kernel(void) __releases(kernel_lock); | 28 | _lock_kernel(const char *func, const char *file, int line) |
| 29 | __acquires(kernel_lock); | ||
| 30 | |||
| 31 | extern void __lockfunc | ||
| 32 | _unlock_kernel(const char *func, const char *file, int line) | ||
| 33 | __releases(kernel_lock); | ||
| 34 | |||
| 35 | #define lock_kernel() do { \ | ||
| 36 | _lock_kernel(__func__, __FILE__, __LINE__); \ | ||
| 37 | } while (0) | ||
| 38 | |||
| 39 | #define unlock_kernel() do { \ | ||
| 40 | _unlock_kernel(__func__, __FILE__, __LINE__); \ | ||
| 41 | } while (0) | ||
| 29 | 42 | ||
| 30 | /* | 43 | /* |
| 31 | * Various legacy drivers don't really need the BKL in a specific | 44 | * Various legacy drivers don't really need the BKL in a specific |
| @@ -41,8 +54,8 @@ static inline void cycle_kernel_lock(void) | |||
| 41 | 54 | ||
| 42 | #else | 55 | #else |
| 43 | 56 | ||
| 44 | #define lock_kernel() do { } while(0) | 57 | #define lock_kernel() |
| 45 | #define unlock_kernel() do { } while(0) | 58 | #define unlock_kernel() |
| 46 | #define release_kernel_lock(task) do { } while(0) | 59 | #define release_kernel_lock(task) do { } while(0) |
| 47 | #define cycle_kernel_lock() do { } while(0) | 60 | #define cycle_kernel_lock() do { } while(0) |
| 48 | #define reacquire_kernel_lock(task) 0 | 61 | #define reacquire_kernel_lock(task) 0 |
diff --git a/include/trace/events/bkl.h b/include/trace/events/bkl.h new file mode 100644 index 000000000000..8abd620a490e --- /dev/null +++ b/include/trace/events/bkl.h | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | #undef TRACE_SYSTEM | ||
| 2 | #define TRACE_SYSTEM bkl | ||
| 3 | |||
| 4 | #if !defined(_TRACE_BKL_H) || defined(TRACE_HEADER_MULTI_READ) | ||
| 5 | #define _TRACE_BKL_H | ||
| 6 | |||
| 7 | #include <linux/tracepoint.h> | ||
| 8 | |||
| 9 | TRACE_EVENT(lock_kernel, | ||
| 10 | |||
| 11 | TP_PROTO(const char *func, const char *file, int line), | ||
| 12 | |||
| 13 | TP_ARGS(func, file, line), | ||
| 14 | |||
| 15 | TP_STRUCT__entry( | ||
| 16 | __field( int, lock_depth ) | ||
| 17 | __field_ext( const char *, func, FILTER_PTR_STRING ) | ||
| 18 | __field_ext( const char *, file, FILTER_PTR_STRING ) | ||
| 19 | __field( int, line ) | ||
| 20 | ), | ||
| 21 | |||
| 22 | TP_fast_assign( | ||
| 23 | /* We want to record the lock_depth after lock is acquired */ | ||
| 24 | __entry->lock_depth = current->lock_depth + 1; | ||
| 25 | __entry->func = func; | ||
| 26 | __entry->file = file; | ||
| 27 | __entry->line = line; | ||
| 28 | ), | ||
| 29 | |||
| 30 | TP_printk("depth: %d, %s:%d %s()", __entry->lock_depth, | ||
| 31 | __entry->file, __entry->line, __entry->func) | ||
| 32 | ); | ||
| 33 | |||
| 34 | TRACE_EVENT(unlock_kernel, | ||
| 35 | |||
| 36 | TP_PROTO(const char *func, const char *file, int line), | ||
| 37 | |||
| 38 | TP_ARGS(func, file, line), | ||
| 39 | |||
| 40 | TP_STRUCT__entry( | ||
| 41 | __field(int, lock_depth) | ||
| 42 | __field(const char *, func) | ||
| 43 | __field(const char *, file) | ||
| 44 | __field(int, line) | ||
| 45 | ), | ||
| 46 | |||
| 47 | TP_fast_assign( | ||
| 48 | __entry->lock_depth = current->lock_depth; | ||
| 49 | __entry->func = func; | ||
| 50 | __entry->file = file; | ||
| 51 | __entry->line = line; | ||
| 52 | ), | ||
| 53 | |||
| 54 | TP_printk("depth: %d, %s:%d %s()", __entry->lock_depth, | ||
| 55 | __entry->file, __entry->line, __entry->func) | ||
| 56 | ); | ||
| 57 | |||
| 58 | #endif /* _TRACE_BKL_H */ | ||
| 59 | |||
| 60 | /* This part must be outside protection */ | ||
| 61 | #include <trace/define_trace.h> | ||
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index f136fe5da07a..1a7f6abd06bf 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -225,7 +225,11 @@ static void ftrace_update_pid_func(void) | |||
| 225 | if (ftrace_trace_function == ftrace_stub) | 225 | if (ftrace_trace_function == ftrace_stub) |
| 226 | return; | 226 | return; |
| 227 | 227 | ||
| 228 | #ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST | ||
| 228 | func = ftrace_trace_function; | 229 | func = ftrace_trace_function; |
| 230 | #else | ||
| 231 | func = __ftrace_trace_function; | ||
| 232 | #endif | ||
| 229 | 233 | ||
| 230 | if (ftrace_pid_trace) { | 234 | if (ftrace_pid_trace) { |
| 231 | set_ftrace_pid_function(func); | 235 | set_ftrace_pid_function(func); |
| @@ -1652,60 +1656,6 @@ ftrace_regex_lseek(struct file *file, loff_t offset, int origin) | |||
| 1652 | return ret; | 1656 | return ret; |
| 1653 | } | 1657 | } |
| 1654 | 1658 | ||
| 1655 | enum { | ||
| 1656 | MATCH_FULL, | ||
| 1657 | MATCH_FRONT_ONLY, | ||
| 1658 | MATCH_MIDDLE_ONLY, | ||
| 1659 | MATCH_END_ONLY, | ||
| 1660 | }; | ||
| 1661 | |||
| 1662 | /* | ||
| 1663 | * (static function - no need for kernel doc) | ||
| 1664 | * | ||
| 1665 | * Pass in a buffer containing a glob and this function will | ||
| 1666 | * set search to point to the search part of the buffer and | ||
| 1667 | * return the type of search it is (see enum above). | ||
| 1668 | * This does modify buff. | ||
| 1669 | * | ||
| 1670 | * Returns enum type. | ||
| 1671 | * search returns the pointer to use for comparison. | ||
| 1672 | * not returns 1 if buff started with a '!' | ||
| 1673 | * 0 otherwise. | ||
| 1674 | */ | ||
| 1675 | static int | ||
| 1676 | ftrace_setup_glob(char *buff, int len, char **search, int *not) | ||
| 1677 | { | ||
| 1678 | int type = MATCH_FULL; | ||
| 1679 | int i; | ||
| 1680 | |||
| 1681 | if (buff[0] == '!') { | ||
| 1682 | *not = 1; | ||
| 1683 | buff++; | ||
| 1684 | len--; | ||
| 1685 | } else | ||
| 1686 | *not = 0; | ||
| 1687 | |||
| 1688 | *search = buff; | ||
| 1689 | |||
| 1690 | for (i = 0; i < len; i++) { | ||
| 1691 | if (buff[i] == '*') { | ||
| 1692 | if (!i) { | ||
| 1693 | *search = buff + 1; | ||
| 1694 | type = MATCH_END_ONLY; | ||
| 1695 | } else { | ||
| 1696 | if (type == MATCH_END_ONLY) | ||
| 1697 | type = MATCH_MIDDLE_ONLY; | ||
| 1698 | else | ||
| 1699 | type = MATCH_FRONT_ONLY; | ||
| 1700 | buff[i] = 0; | ||
| 1701 | break; | ||
| 1702 | } | ||
| 1703 | } | ||
| 1704 | } | ||
| 1705 | |||
| 1706 | return type; | ||
| 1707 | } | ||
| 1708 | |||
| 1709 | static int ftrace_match(char *str, char *regex, int len, int type) | 1659 | static int ftrace_match(char *str, char *regex, int len, int type) |
| 1710 | { | 1660 | { |
| 1711 | int matched = 0; | 1661 | int matched = 0; |
| @@ -1754,7 +1704,7 @@ static void ftrace_match_records(char *buff, int len, int enable) | |||
| 1754 | int not; | 1704 | int not; |
| 1755 | 1705 | ||
| 1756 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; | 1706 | flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; |
| 1757 | type = ftrace_setup_glob(buff, len, &search, ¬); | 1707 | type = filter_parse_regex(buff, len, &search, ¬); |
| 1758 | 1708 | ||
| 1759 | search_len = strlen(search); | 1709 | search_len = strlen(search); |
| 1760 | 1710 | ||
| @@ -1822,7 +1772,7 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable) | |||
| 1822 | } | 1772 | } |
| 1823 | 1773 | ||
| 1824 | if (strlen(buff)) { | 1774 | if (strlen(buff)) { |
| 1825 | type = ftrace_setup_glob(buff, strlen(buff), &search, ¬); | 1775 | type = filter_parse_regex(buff, strlen(buff), &search, ¬); |
| 1826 | search_len = strlen(search); | 1776 | search_len = strlen(search); |
| 1827 | } | 1777 | } |
| 1828 | 1778 | ||
| @@ -1987,7 +1937,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
| 1987 | int count = 0; | 1937 | int count = 0; |
| 1988 | char *search; | 1938 | char *search; |
| 1989 | 1939 | ||
| 1990 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | 1940 | type = filter_parse_regex(glob, strlen(glob), &search, ¬); |
| 1991 | len = strlen(search); | 1941 | len = strlen(search); |
| 1992 | 1942 | ||
| 1993 | /* we do not support '!' for function probes */ | 1943 | /* we do not support '!' for function probes */ |
| @@ -2064,7 +2014,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, | |||
| 2064 | else if (glob) { | 2014 | else if (glob) { |
| 2065 | int not; | 2015 | int not; |
| 2066 | 2016 | ||
| 2067 | type = ftrace_setup_glob(glob, strlen(glob), &search, ¬); | 2017 | type = filter_parse_regex(glob, strlen(glob), &search, ¬); |
| 2068 | len = strlen(search); | 2018 | len = strlen(search); |
| 2069 | 2019 | ||
| 2070 | /* we do not support '!' for function probes */ | 2020 | /* we do not support '!' for function probes */ |
| @@ -2509,7 +2459,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer) | |||
| 2509 | return -ENODEV; | 2459 | return -ENODEV; |
| 2510 | 2460 | ||
| 2511 | /* decode regex */ | 2461 | /* decode regex */ |
| 2512 | type = ftrace_setup_glob(buffer, strlen(buffer), &search, ¬); | 2462 | type = filter_parse_regex(buffer, strlen(buffer), &search, ¬); |
| 2513 | if (not) | 2463 | if (not) |
| 2514 | return -EINVAL; | 2464 | return -EINVAL; |
| 2515 | 2465 | ||
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 405cb850b75d..365fb19d9e11 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -699,22 +699,40 @@ struct event_subsystem { | |||
| 699 | }; | 699 | }; |
| 700 | 700 | ||
| 701 | struct filter_pred; | 701 | struct filter_pred; |
| 702 | struct regex; | ||
| 702 | 703 | ||
| 703 | typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, | 704 | typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, |
| 704 | int val1, int val2); | 705 | int val1, int val2); |
| 705 | 706 | ||
| 707 | typedef int (*regex_match_func)(char *str, struct regex *r, int len); | ||
| 708 | |||
| 709 | enum regex_type { | ||
| 710 | MATCH_FULL, | ||
| 711 | MATCH_FRONT_ONLY, | ||
| 712 | MATCH_MIDDLE_ONLY, | ||
| 713 | MATCH_END_ONLY, | ||
| 714 | }; | ||
| 715 | |||
| 716 | struct regex { | ||
| 717 | char pattern[MAX_FILTER_STR_VAL]; | ||
| 718 | int len; | ||
| 719 | int field_len; | ||
| 720 | regex_match_func match; | ||
| 721 | }; | ||
| 722 | |||
| 706 | struct filter_pred { | 723 | struct filter_pred { |
| 707 | filter_pred_fn_t fn; | 724 | filter_pred_fn_t fn; |
| 708 | u64 val; | 725 | u64 val; |
| 709 | char str_val[MAX_FILTER_STR_VAL]; | 726 | struct regex regex; |
| 710 | int str_len; | 727 | char *field_name; |
| 711 | char *field_name; | 728 | int offset; |
| 712 | int offset; | 729 | int not; |
| 713 | int not; | 730 | int op; |
| 714 | int op; | 731 | int pop_n; |
| 715 | int pop_n; | ||
| 716 | }; | 732 | }; |
| 717 | 733 | ||
| 734 | extern enum regex_type | ||
| 735 | filter_parse_regex(char *buff, int len, char **search, int *not); | ||
| 718 | extern void print_event_filter(struct ftrace_event_call *call, | 736 | extern void print_event_filter(struct ftrace_event_call *call, |
| 719 | struct trace_seq *s); | 737 | struct trace_seq *s); |
| 720 | extern int apply_event_filter(struct ftrace_event_call *call, | 738 | extern int apply_event_filter(struct ftrace_event_call *call, |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index d128f65778e6..5e9ffc33f6db 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -878,9 +878,9 @@ event_subsystem_dir(const char *name, struct dentry *d_events) | |||
| 878 | "'%s/filter' entry\n", name); | 878 | "'%s/filter' entry\n", name); |
| 879 | } | 879 | } |
| 880 | 880 | ||
| 881 | entry = trace_create_file("enable", 0644, system->entry, | 881 | trace_create_file("enable", 0644, system->entry, |
| 882 | (void *)system->name, | 882 | (void *)system->name, |
| 883 | &ftrace_system_enable_fops); | 883 | &ftrace_system_enable_fops); |
| 884 | 884 | ||
| 885 | return system->entry; | 885 | return system->entry; |
| 886 | } | 886 | } |
| @@ -892,7 +892,6 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
| 892 | const struct file_operations *filter, | 892 | const struct file_operations *filter, |
| 893 | const struct file_operations *format) | 893 | const struct file_operations *format) |
| 894 | { | 894 | { |
| 895 | struct dentry *entry; | ||
| 896 | int ret; | 895 | int ret; |
| 897 | 896 | ||
| 898 | /* | 897 | /* |
| @@ -910,12 +909,12 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
| 910 | } | 909 | } |
| 911 | 910 | ||
| 912 | if (call->regfunc) | 911 | if (call->regfunc) |
| 913 | entry = trace_create_file("enable", 0644, call->dir, call, | 912 | trace_create_file("enable", 0644, call->dir, call, |
| 914 | enable); | 913 | enable); |
| 915 | 914 | ||
| 916 | if (call->id && call->profile_enable) | 915 | if (call->id && call->profile_enable) |
| 917 | entry = trace_create_file("id", 0444, call->dir, call, | 916 | trace_create_file("id", 0444, call->dir, call, |
| 918 | id); | 917 | id); |
| 919 | 918 | ||
| 920 | if (call->define_fields) { | 919 | if (call->define_fields) { |
| 921 | ret = call->define_fields(call); | 920 | ret = call->define_fields(call); |
| @@ -924,16 +923,16 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
| 924 | " events/%s\n", call->name); | 923 | " events/%s\n", call->name); |
| 925 | return ret; | 924 | return ret; |
| 926 | } | 925 | } |
| 927 | entry = trace_create_file("filter", 0644, call->dir, call, | 926 | trace_create_file("filter", 0644, call->dir, call, |
| 928 | filter); | 927 | filter); |
| 929 | } | 928 | } |
| 930 | 929 | ||
| 931 | /* A trace may not want to export its format */ | 930 | /* A trace may not want to export its format */ |
| 932 | if (!call->show_format) | 931 | if (!call->show_format) |
| 933 | return 0; | 932 | return 0; |
| 934 | 933 | ||
| 935 | entry = trace_create_file("format", 0444, call->dir, call, | 934 | trace_create_file("format", 0444, call->dir, call, |
| 936 | format); | 935 | format); |
| 937 | 936 | ||
| 938 | return 0; | 937 | return 0; |
| 939 | } | 938 | } |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 98a6cc5c64ed..92672016da28 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
| @@ -18,8 +18,6 @@ | |||
| 18 | * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> | 18 | * Copyright (C) 2009 Tom Zanussi <tzanussi@gmail.com> |
| 19 | */ | 19 | */ |
| 20 | 20 | ||
| 21 | #include <linux/debugfs.h> | ||
| 22 | #include <linux/uaccess.h> | ||
| 23 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 24 | #include <linux/ctype.h> | 22 | #include <linux/ctype.h> |
| 25 | #include <linux/mutex.h> | 23 | #include <linux/mutex.h> |
| @@ -197,9 +195,9 @@ static int filter_pred_string(struct filter_pred *pred, void *event, | |||
| 197 | char *addr = (char *)(event + pred->offset); | 195 | char *addr = (char *)(event + pred->offset); |
| 198 | int cmp, match; | 196 | int cmp, match; |
| 199 | 197 | ||
| 200 | cmp = strncmp(addr, pred->str_val, pred->str_len); | 198 | cmp = pred->regex.match(addr, &pred->regex, pred->regex.field_len); |
| 201 | 199 | ||
| 202 | match = (!cmp) ^ pred->not; | 200 | match = cmp ^ pred->not; |
| 203 | 201 | ||
| 204 | return match; | 202 | return match; |
| 205 | } | 203 | } |
| @@ -211,9 +209,9 @@ static int filter_pred_pchar(struct filter_pred *pred, void *event, | |||
| 211 | char **addr = (char **)(event + pred->offset); | 209 | char **addr = (char **)(event + pred->offset); |
| 212 | int cmp, match; | 210 | int cmp, match; |
| 213 | 211 | ||
| 214 | cmp = strncmp(*addr, pred->str_val, pred->str_len); | 212 | cmp = pred->regex.match(*addr, &pred->regex, pred->regex.field_len); |
| 215 | 213 | ||
| 216 | match = (!cmp) ^ pred->not; | 214 | match = cmp ^ pred->not; |
| 217 | 215 | ||
| 218 | return match; | 216 | return match; |
| 219 | } | 217 | } |
| @@ -237,9 +235,9 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event, | |||
| 237 | char *addr = (char *)(event + str_loc); | 235 | char *addr = (char *)(event + str_loc); |
| 238 | int cmp, match; | 236 | int cmp, match; |
| 239 | 237 | ||
| 240 | cmp = strncmp(addr, pred->str_val, str_len); | 238 | cmp = pred->regex.match(addr, &pred->regex, str_len); |
| 241 | 239 | ||
| 242 | match = (!cmp) ^ pred->not; | 240 | match = cmp ^ pred->not; |
| 243 | 241 | ||
| 244 | return match; | 242 | return match; |
| 245 | } | 243 | } |
| @@ -250,6 +248,124 @@ static int filter_pred_none(struct filter_pred *pred, void *event, | |||
| 250 | return 0; | 248 | return 0; |
| 251 | } | 249 | } |
| 252 | 250 | ||
| 251 | /* Basic regex callbacks */ | ||
| 252 | static int regex_match_full(char *str, struct regex *r, int len) | ||
| 253 | { | ||
| 254 | if (strncmp(str, r->pattern, len) == 0) | ||
| 255 | return 1; | ||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | static int regex_match_front(char *str, struct regex *r, int len) | ||
| 260 | { | ||
| 261 | if (strncmp(str, r->pattern, len) == 0) | ||
| 262 | return 1; | ||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | static int regex_match_middle(char *str, struct regex *r, int len) | ||
| 267 | { | ||
| 268 | if (strstr(str, r->pattern)) | ||
| 269 | return 1; | ||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | |||
| 273 | static int regex_match_end(char *str, struct regex *r, int len) | ||
| 274 | { | ||
| 275 | char *ptr = strstr(str, r->pattern); | ||
| 276 | |||
| 277 | if (ptr && (ptr[r->len] == 0)) | ||
| 278 | return 1; | ||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | /** | ||
| 283 | * filter_parse_regex - parse a basic regex | ||
| 284 | * @buff: the raw regex | ||
| 285 | * @len: length of the regex | ||
| 286 | * @search: will point to the beginning of the string to compare | ||
| 287 | * @not: tell whether the match will have to be inverted | ||
| 288 | * | ||
| 289 | * This passes in a buffer containing a regex and this function will | ||
| 290 | * set search to point to the search part of the buffer and | ||
| 291 | * return the type of search it is (see enum above). | ||
| 292 | * This does modify buff. | ||
| 293 | * | ||
| 294 | * Returns enum type. | ||
| 295 | * search returns the pointer to use for comparison. | ||
| 296 | * not returns 1 if buff started with a '!' | ||
| 297 | * 0 otherwise. | ||
| 298 | */ | ||
| 299 | enum regex_type filter_parse_regex(char *buff, int len, char **search, int *not) | ||
| 300 | { | ||
| 301 | int type = MATCH_FULL; | ||
| 302 | int i; | ||
| 303 | |||
| 304 | if (buff[0] == '!') { | ||
| 305 | *not = 1; | ||
| 306 | buff++; | ||
| 307 | len--; | ||
| 308 | } else | ||
| 309 | *not = 0; | ||
| 310 | |||
| 311 | *search = buff; | ||
| 312 | |||
| 313 | for (i = 0; i < len; i++) { | ||
| 314 | if (buff[i] == '*') { | ||
| 315 | if (!i) { | ||
| 316 | *search = buff + 1; | ||
| 317 | type = MATCH_END_ONLY; | ||
| 318 | } else { | ||
| 319 | if (type == MATCH_END_ONLY) | ||
| 320 | type = MATCH_MIDDLE_ONLY; | ||
| 321 | else | ||
| 322 | type = MATCH_FRONT_ONLY; | ||
| 323 | buff[i] = 0; | ||
| 324 | break; | ||
| 325 | } | ||
| 326 | } | ||
| 327 | } | ||
| 328 | |||
| 329 | return type; | ||
| 330 | } | ||
| 331 | |||
| 332 | static int filter_build_regex(struct filter_pred *pred) | ||
| 333 | { | ||
| 334 | struct regex *r = &pred->regex; | ||
| 335 | char *search, *dup; | ||
| 336 | enum regex_type type; | ||
| 337 | int not; | ||
| 338 | |||
| 339 | type = filter_parse_regex(r->pattern, r->len, &search, ¬); | ||
| 340 | dup = kstrdup(search, GFP_KERNEL); | ||
| 341 | if (!dup) | ||
| 342 | return -ENOMEM; | ||
| 343 | |||
| 344 | strcpy(r->pattern, dup); | ||
| 345 | kfree(dup); | ||
| 346 | |||
| 347 | r->len = strlen(r->pattern); | ||
| 348 | |||
| 349 | switch (type) { | ||
| 350 | case MATCH_FULL: | ||
| 351 | r->match = regex_match_full; | ||
| 352 | break; | ||
| 353 | case MATCH_FRONT_ONLY: | ||
| 354 | r->match = regex_match_front; | ||
| 355 | break; | ||
| 356 | case MATCH_MIDDLE_ONLY: | ||
| 357 | r->match = regex_match_middle; | ||
| 358 | break; | ||
| 359 | case MATCH_END_ONLY: | ||
| 360 | r->match = regex_match_end; | ||
| 361 | break; | ||
| 362 | } | ||
| 363 | |||
| 364 | pred->not ^= not; | ||
| 365 | |||
| 366 | return 0; | ||
| 367 | } | ||
| 368 | |||
| 253 | /* return 1 if event matches, 0 otherwise (discard) */ | 369 | /* return 1 if event matches, 0 otherwise (discard) */ |
| 254 | int filter_match_preds(struct ftrace_event_call *call, void *rec) | 370 | int filter_match_preds(struct ftrace_event_call *call, void *rec) |
| 255 | { | 371 | { |
| @@ -396,7 +512,7 @@ static void filter_clear_pred(struct filter_pred *pred) | |||
| 396 | { | 512 | { |
| 397 | kfree(pred->field_name); | 513 | kfree(pred->field_name); |
| 398 | pred->field_name = NULL; | 514 | pred->field_name = NULL; |
| 399 | pred->str_len = 0; | 515 | pred->regex.len = 0; |
| 400 | } | 516 | } |
| 401 | 517 | ||
| 402 | static int filter_set_pred(struct filter_pred *dest, | 518 | static int filter_set_pred(struct filter_pred *dest, |
| @@ -660,21 +776,24 @@ static int filter_add_pred(struct filter_parse_state *ps, | |||
| 660 | } | 776 | } |
| 661 | 777 | ||
| 662 | if (is_string_field(field)) { | 778 | if (is_string_field(field)) { |
| 663 | pred->str_len = field->size; | 779 | ret = filter_build_regex(pred); |
| 780 | if (ret) | ||
| 781 | return ret; | ||
| 664 | 782 | ||
| 665 | if (field->filter_type == FILTER_STATIC_STRING) | 783 | if (field->filter_type == FILTER_STATIC_STRING) { |
| 666 | fn = filter_pred_string; | 784 | fn = filter_pred_string; |
| 667 | else if (field->filter_type == FILTER_DYN_STRING) | 785 | pred->regex.field_len = field->size; |
| 668 | fn = filter_pred_strloc; | 786 | } else if (field->filter_type == FILTER_DYN_STRING) |
| 787 | fn = filter_pred_strloc; | ||
| 669 | else { | 788 | else { |
| 670 | fn = filter_pred_pchar; | 789 | fn = filter_pred_pchar; |
| 671 | pred->str_len = strlen(pred->str_val); | 790 | pred->regex.field_len = strlen(pred->regex.pattern); |
| 672 | } | 791 | } |
| 673 | } else { | 792 | } else { |
| 674 | if (field->is_signed) | 793 | if (field->is_signed) |
| 675 | ret = strict_strtoll(pred->str_val, 0, &val); | 794 | ret = strict_strtoll(pred->regex.pattern, 0, &val); |
| 676 | else | 795 | else |
| 677 | ret = strict_strtoull(pred->str_val, 0, &val); | 796 | ret = strict_strtoull(pred->regex.pattern, 0, &val); |
| 678 | if (ret) { | 797 | if (ret) { |
| 679 | parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0); | 798 | parse_error(ps, FILT_ERR_ILLEGAL_INTVAL, 0); |
| 680 | return -EINVAL; | 799 | return -EINVAL; |
| @@ -1045,8 +1164,8 @@ static struct filter_pred *create_pred(int op, char *operand1, char *operand2) | |||
| 1045 | return NULL; | 1164 | return NULL; |
| 1046 | } | 1165 | } |
| 1047 | 1166 | ||
| 1048 | strcpy(pred->str_val, operand2); | 1167 | strcpy(pred->regex.pattern, operand2); |
| 1049 | pred->str_len = strlen(operand2); | 1168 | pred->regex.len = strlen(pred->regex.pattern); |
| 1050 | 1169 | ||
| 1051 | pred->op = op; | 1170 | pred->op = op; |
| 1052 | 1171 | ||
diff --git a/lib/kernel_lock.c b/lib/kernel_lock.c index 39f1029e3525..4ebfa5a164d7 100644 --- a/lib/kernel_lock.c +++ b/lib/kernel_lock.c | |||
| @@ -5,10 +5,13 @@ | |||
| 5 | * relegated to obsolescence, but used by various less | 5 | * relegated to obsolescence, but used by various less |
| 6 | * important (or lazy) subsystems. | 6 | * important (or lazy) subsystems. |
| 7 | */ | 7 | */ |
| 8 | #include <linux/smp_lock.h> | ||
| 9 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 10 | #include <linux/kallsyms.h> | 9 | #include <linux/kallsyms.h> |
| 11 | #include <linux/semaphore.h> | 10 | #include <linux/semaphore.h> |
| 11 | #include <linux/smp_lock.h> | ||
| 12 | |||
| 13 | #define CREATE_TRACE_POINTS | ||
| 14 | #include <trace/events/bkl.h> | ||
| 12 | 15 | ||
| 13 | /* | 16 | /* |
| 14 | * The 'big kernel lock' | 17 | * The 'big kernel lock' |
| @@ -113,21 +116,26 @@ static inline void __unlock_kernel(void) | |||
| 113 | * This cannot happen asynchronously, so we only need to | 116 | * This cannot happen asynchronously, so we only need to |
| 114 | * worry about other CPU's. | 117 | * worry about other CPU's. |
| 115 | */ | 118 | */ |
| 116 | void __lockfunc lock_kernel(void) | 119 | void __lockfunc _lock_kernel(const char *func, const char *file, int line) |
| 117 | { | 120 | { |
| 118 | int depth = current->lock_depth+1; | 121 | int depth = current->lock_depth + 1; |
| 122 | |||
| 123 | trace_lock_kernel(func, file, line); | ||
| 124 | |||
| 119 | if (likely(!depth)) | 125 | if (likely(!depth)) |
| 120 | __lock_kernel(); | 126 | __lock_kernel(); |
| 121 | current->lock_depth = depth; | 127 | current->lock_depth = depth; |
| 122 | } | 128 | } |
| 123 | 129 | ||
| 124 | void __lockfunc unlock_kernel(void) | 130 | void __lockfunc _unlock_kernel(const char *func, const char *file, int line) |
| 125 | { | 131 | { |
| 126 | BUG_ON(current->lock_depth < 0); | 132 | BUG_ON(current->lock_depth < 0); |
| 127 | if (likely(--current->lock_depth < 0)) | 133 | if (likely(--current->lock_depth < 0)) |
| 128 | __unlock_kernel(); | 134 | __unlock_kernel(); |
| 135 | |||
| 136 | trace_unlock_kernel(func, file, line); | ||
| 129 | } | 137 | } |
| 130 | 138 | ||
| 131 | EXPORT_SYMBOL(lock_kernel); | 139 | EXPORT_SYMBOL(_lock_kernel); |
| 132 | EXPORT_SYMBOL(unlock_kernel); | 140 | EXPORT_SYMBOL(_unlock_kernel); |
| 133 | 141 | ||
