aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/smp_lock.h21
-rw-r--r--include/trace/events/bkl.h61
-rw-r--r--kernel/trace/ftrace.c64
-rw-r--r--kernel/trace/trace.h36
-rw-r--r--kernel/trace/trace_events.c23
-rw-r--r--kernel/trace/trace_events_filter.c155
-rw-r--r--lib/kernel_lock.c20
7 files changed, 272 insertions, 108 deletions
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
27extern void __lockfunc lock_kernel(void) __acquires(kernel_lock); 27extern void __lockfunc
28extern void __lockfunc unlock_kernel(void) __releases(kernel_lock); 28_lock_kernel(const char *func, const char *file, int line)
29__acquires(kernel_lock);
30
31extern 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
9TRACE_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
34TRACE_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 3724756e41ca..9a72853a8f0a 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1661,60 +1661,6 @@ ftrace_regex_lseek(struct file *file, loff_t offset, int origin)
1661 return ret; 1661 return ret;
1662} 1662}
1663 1663
1664enum {
1665 MATCH_FULL,
1666 MATCH_FRONT_ONLY,
1667 MATCH_MIDDLE_ONLY,
1668 MATCH_END_ONLY,
1669};
1670
1671/*
1672 * (static function - no need for kernel doc)
1673 *
1674 * Pass in a buffer containing a glob and this function will
1675 * set search to point to the search part of the buffer and
1676 * return the type of search it is (see enum above).
1677 * This does modify buff.
1678 *
1679 * Returns enum type.
1680 * search returns the pointer to use for comparison.
1681 * not returns 1 if buff started with a '!'
1682 * 0 otherwise.
1683 */
1684static int
1685ftrace_setup_glob(char *buff, int len, char **search, int *not)
1686{
1687 int type = MATCH_FULL;
1688 int i;
1689
1690 if (buff[0] == '!') {
1691 *not = 1;
1692 buff++;
1693 len--;
1694 } else
1695 *not = 0;
1696
1697 *search = buff;
1698
1699 for (i = 0; i < len; i++) {
1700 if (buff[i] == '*') {
1701 if (!i) {
1702 *search = buff + 1;
1703 type = MATCH_END_ONLY;
1704 } else {
1705 if (type == MATCH_END_ONLY)
1706 type = MATCH_MIDDLE_ONLY;
1707 else
1708 type = MATCH_FRONT_ONLY;
1709 buff[i] = 0;
1710 break;
1711 }
1712 }
1713 }
1714
1715 return type;
1716}
1717
1718static int ftrace_match(char *str, char *regex, int len, int type) 1664static int ftrace_match(char *str, char *regex, int len, int type)
1719{ 1665{
1720 int matched = 0; 1666 int matched = 0;
@@ -1763,7 +1709,7 @@ static void ftrace_match_records(char *buff, int len, int enable)
1763 int not; 1709 int not;
1764 1710
1765 flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE; 1711 flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;
1766 type = ftrace_setup_glob(buff, len, &search, &not); 1712 type = filter_parse_regex(buff, len, &search, &not);
1767 1713
1768 search_len = strlen(search); 1714 search_len = strlen(search);
1769 1715
@@ -1831,7 +1777,7 @@ static void ftrace_match_module_records(char *buff, char *mod, int enable)
1831 } 1777 }
1832 1778
1833 if (strlen(buff)) { 1779 if (strlen(buff)) {
1834 type = ftrace_setup_glob(buff, strlen(buff), &search, &not); 1780 type = filter_parse_regex(buff, strlen(buff), &search, &not);
1835 search_len = strlen(search); 1781 search_len = strlen(search);
1836 } 1782 }
1837 1783
@@ -1996,7 +1942,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
1996 int count = 0; 1942 int count = 0;
1997 char *search; 1943 char *search;
1998 1944
1999 type = ftrace_setup_glob(glob, strlen(glob), &search, &not); 1945 type = filter_parse_regex(glob, strlen(glob), &search, &not);
2000 len = strlen(search); 1946 len = strlen(search);
2001 1947
2002 /* we do not support '!' for function probes */ 1948 /* we do not support '!' for function probes */
@@ -2073,7 +2019,7 @@ __unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,
2073 else if (glob) { 2019 else if (glob) {
2074 int not; 2020 int not;
2075 2021
2076 type = ftrace_setup_glob(glob, strlen(glob), &search, &not); 2022 type = filter_parse_regex(glob, strlen(glob), &search, &not);
2077 len = strlen(search); 2023 len = strlen(search);
2078 2024
2079 /* we do not support '!' for function probes */ 2025 /* we do not support '!' for function probes */
@@ -2518,7 +2464,7 @@ ftrace_set_func(unsigned long *array, int *idx, char *buffer)
2518 return -ENODEV; 2464 return -ENODEV;
2519 2465
2520 /* decode regex */ 2466 /* decode regex */
2521 type = ftrace_setup_glob(buffer, strlen(buffer), &search, &not); 2467 type = filter_parse_regex(buffer, strlen(buffer), &search, &not);
2522 if (not) 2468 if (not)
2523 return -EINVAL; 2469 return -EINVAL;
2524 2470
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
701struct filter_pred; 701struct filter_pred;
702struct regex;
702 703
703typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event, 704typedef int (*filter_pred_fn_t) (struct filter_pred *pred, void *event,
704 int val1, int val2); 705 int val1, int val2);
705 706
707typedef int (*regex_match_func)(char *str, struct regex *r, int len);
708
709enum regex_type {
710 MATCH_FULL,
711 MATCH_FRONT_ONLY,
712 MATCH_MIDDLE_ONLY,
713 MATCH_END_ONLY,
714};
715
716struct regex {
717 char pattern[MAX_FILTER_STR_VAL];
718 int len;
719 int field_len;
720 regex_match_func match;
721};
722
706struct filter_pred { 723struct 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
734extern enum regex_type
735filter_parse_regex(char *buff, int len, char **search, int *not);
718extern void print_event_filter(struct ftrace_event_call *call, 736extern void print_event_filter(struct ftrace_event_call *call,
719 struct trace_seq *s); 737 struct trace_seq *s);
720extern int apply_event_filter(struct ftrace_event_call *call, 738extern 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 23245785927f..8c194de675b0 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 */
252static 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
259static 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
266static 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
273static 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 */
299enum 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
332static 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, &not);
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) */
254int filter_match_preds(struct ftrace_event_call *call, void *rec) 370int 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
402static int filter_set_pred(struct filter_pred *dest, 518static 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;
@@ -1044,8 +1163,8 @@ static struct filter_pred *create_pred(int op, char *operand1, char *operand2)
1044 return NULL; 1163 return NULL;
1045 } 1164 }
1046 1165
1047 strcpy(pred->str_val, operand2); 1166 strcpy(pred->regex.pattern, operand2);
1048 pred->str_len = strlen(operand2); 1167 pred->regex.len = strlen(pred->regex.pattern);
1049 1168
1050 pred->op = op; 1169 pred->op = op;
1051 1170
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 */
116void __lockfunc lock_kernel(void) 119void __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
124void __lockfunc unlock_kernel(void) 130void __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
131EXPORT_SYMBOL(lock_kernel); 139EXPORT_SYMBOL(_lock_kernel);
132EXPORT_SYMBOL(unlock_kernel); 140EXPORT_SYMBOL(_unlock_kernel);
133 141