diff options
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/Kconfig | 4 | ||||
| -rw-r--r-- | kernel/trace/ftrace.c | 6 | ||||
| -rw-r--r-- | kernel/trace/ring_buffer.c | 28 | ||||
| -rw-r--r-- | kernel/trace/trace.c | 5 | ||||
| -rw-r--r-- | kernel/trace/trace_events_filter.c | 29 | ||||
| -rw-r--r-- | kernel/trace/trace_kprobe.c | 2 | ||||
| -rw-r--r-- | kernel/trace/trace_stack.c | 24 |
7 files changed, 77 insertions, 21 deletions
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index 6c22d8a2f289..60e2ce0181ee 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig | |||
| @@ -27,9 +27,7 @@ config HAVE_FUNCTION_GRAPH_TRACER | |||
| 27 | config HAVE_FUNCTION_GRAPH_FP_TEST | 27 | config HAVE_FUNCTION_GRAPH_FP_TEST |
| 28 | bool | 28 | bool |
| 29 | help | 29 | help |
| 30 | An arch may pass in a unique value (frame pointer) to both the | 30 | See Documentation/trace/ftrace-design.txt |
| 31 | entering and exiting of a function. On exit, the value is compared | ||
| 32 | and if it does not match, then it will panic the kernel. | ||
| 33 | 31 | ||
| 34 | config HAVE_FUNCTION_TRACE_MCOUNT_TEST | 32 | config HAVE_FUNCTION_TRACE_MCOUNT_TEST |
| 35 | bool | 33 | bool |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 7968762c8167..1e6640f80454 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -1690,7 +1690,7 @@ ftrace_regex_lseek(struct file *file, loff_t offset, int origin) | |||
| 1690 | static int ftrace_match(char *str, char *regex, int len, int type) | 1690 | static int ftrace_match(char *str, char *regex, int len, int type) |
| 1691 | { | 1691 | { |
| 1692 | int matched = 0; | 1692 | int matched = 0; |
| 1693 | char *ptr; | 1693 | int slen; |
| 1694 | 1694 | ||
| 1695 | switch (type) { | 1695 | switch (type) { |
| 1696 | case MATCH_FULL: | 1696 | case MATCH_FULL: |
| @@ -1706,8 +1706,8 @@ static int ftrace_match(char *str, char *regex, int len, int type) | |||
| 1706 | matched = 1; | 1706 | matched = 1; |
| 1707 | break; | 1707 | break; |
| 1708 | case MATCH_END_ONLY: | 1708 | case MATCH_END_ONLY: |
| 1709 | ptr = strstr(str, regex); | 1709 | slen = strlen(str); |
| 1710 | if (ptr && (ptr[len] == 0)) | 1710 | if (slen >= len && memcmp(str + slen - len, regex, len) == 0) |
| 1711 | matched = 1; | 1711 | matched = 1; |
| 1712 | break; | 1712 | break; |
| 1713 | } | 1713 | } |
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 2326b04c95c4..8c1b2d290718 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
| @@ -464,6 +464,8 @@ struct ring_buffer_iter { | |||
| 464 | struct ring_buffer_per_cpu *cpu_buffer; | 464 | struct ring_buffer_per_cpu *cpu_buffer; |
| 465 | unsigned long head; | 465 | unsigned long head; |
| 466 | struct buffer_page *head_page; | 466 | struct buffer_page *head_page; |
| 467 | struct buffer_page *cache_reader_page; | ||
| 468 | unsigned long cache_read; | ||
| 467 | u64 read_stamp; | 469 | u64 read_stamp; |
| 468 | }; | 470 | }; |
| 469 | 471 | ||
| @@ -2716,6 +2718,8 @@ static void rb_iter_reset(struct ring_buffer_iter *iter) | |||
| 2716 | iter->read_stamp = cpu_buffer->read_stamp; | 2718 | iter->read_stamp = cpu_buffer->read_stamp; |
| 2717 | else | 2719 | else |
| 2718 | iter->read_stamp = iter->head_page->page->time_stamp; | 2720 | iter->read_stamp = iter->head_page->page->time_stamp; |
| 2721 | iter->cache_reader_page = cpu_buffer->reader_page; | ||
| 2722 | iter->cache_read = cpu_buffer->read; | ||
| 2719 | } | 2723 | } |
| 2720 | 2724 | ||
| 2721 | /** | 2725 | /** |
| @@ -2869,7 +2873,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) | |||
| 2869 | * Splice the empty reader page into the list around the head. | 2873 | * Splice the empty reader page into the list around the head. |
| 2870 | */ | 2874 | */ |
| 2871 | reader = rb_set_head_page(cpu_buffer); | 2875 | reader = rb_set_head_page(cpu_buffer); |
| 2872 | cpu_buffer->reader_page->list.next = reader->list.next; | 2876 | cpu_buffer->reader_page->list.next = rb_list_head(reader->list.next); |
| 2873 | cpu_buffer->reader_page->list.prev = reader->list.prev; | 2877 | cpu_buffer->reader_page->list.prev = reader->list.prev; |
| 2874 | 2878 | ||
| 2875 | /* | 2879 | /* |
| @@ -2906,7 +2910,7 @@ rb_get_reader_page(struct ring_buffer_per_cpu *cpu_buffer) | |||
| 2906 | * | 2910 | * |
| 2907 | * Now make the new head point back to the reader page. | 2911 | * Now make the new head point back to the reader page. |
| 2908 | */ | 2912 | */ |
| 2909 | reader->list.next->prev = &cpu_buffer->reader_page->list; | 2913 | rb_list_head(reader->list.next)->prev = &cpu_buffer->reader_page->list; |
| 2910 | rb_inc_page(cpu_buffer, &cpu_buffer->head_page); | 2914 | rb_inc_page(cpu_buffer, &cpu_buffer->head_page); |
| 2911 | 2915 | ||
| 2912 | /* Finally update the reader page to the new head */ | 2916 | /* Finally update the reader page to the new head */ |
| @@ -3060,13 +3064,22 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) | |||
| 3060 | struct ring_buffer_event *event; | 3064 | struct ring_buffer_event *event; |
| 3061 | int nr_loops = 0; | 3065 | int nr_loops = 0; |
| 3062 | 3066 | ||
| 3063 | if (ring_buffer_iter_empty(iter)) | ||
| 3064 | return NULL; | ||
| 3065 | |||
| 3066 | cpu_buffer = iter->cpu_buffer; | 3067 | cpu_buffer = iter->cpu_buffer; |
| 3067 | buffer = cpu_buffer->buffer; | 3068 | buffer = cpu_buffer->buffer; |
| 3068 | 3069 | ||
| 3070 | /* | ||
| 3071 | * Check if someone performed a consuming read to | ||
| 3072 | * the buffer. A consuming read invalidates the iterator | ||
| 3073 | * and we need to reset the iterator in this case. | ||
| 3074 | */ | ||
| 3075 | if (unlikely(iter->cache_read != cpu_buffer->read || | ||
| 3076 | iter->cache_reader_page != cpu_buffer->reader_page)) | ||
| 3077 | rb_iter_reset(iter); | ||
| 3078 | |||
| 3069 | again: | 3079 | again: |
| 3080 | if (ring_buffer_iter_empty(iter)) | ||
| 3081 | return NULL; | ||
| 3082 | |||
| 3070 | /* | 3083 | /* |
| 3071 | * We repeat when a timestamp is encountered. | 3084 | * We repeat when a timestamp is encountered. |
| 3072 | * We can get multiple timestamps by nested interrupts or also | 3085 | * We can get multiple timestamps by nested interrupts or also |
| @@ -3081,6 +3094,11 @@ rb_iter_peek(struct ring_buffer_iter *iter, u64 *ts) | |||
| 3081 | if (rb_per_cpu_empty(cpu_buffer)) | 3094 | if (rb_per_cpu_empty(cpu_buffer)) |
| 3082 | return NULL; | 3095 | return NULL; |
| 3083 | 3096 | ||
| 3097 | if (iter->head >= local_read(&iter->head_page->page->commit)) { | ||
| 3098 | rb_inc_iter(iter); | ||
| 3099 | goto again; | ||
| 3100 | } | ||
| 3101 | |||
| 3084 | event = rb_iter_head_event(iter); | 3102 | event = rb_iter_head_event(iter); |
| 3085 | 3103 | ||
| 3086 | switch (event->type_len) { | 3104 | switch (event->type_len) { |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 0df1b0f2cb9e..eac6875cb990 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -951,6 +951,11 @@ void trace_find_cmdline(int pid, char comm[]) | |||
| 951 | return; | 951 | return; |
| 952 | } | 952 | } |
| 953 | 953 | ||
| 954 | if (WARN_ON_ONCE(pid < 0)) { | ||
| 955 | strcpy(comm, "<XXX>"); | ||
| 956 | return; | ||
| 957 | } | ||
| 958 | |||
| 954 | if (pid > PID_MAX_DEFAULT) { | 959 | if (pid > PID_MAX_DEFAULT) { |
| 955 | strcpy(comm, "<...>"); | 960 | strcpy(comm, "<...>"); |
| 956 | return; | 961 | return; |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 50504cb228de..e42af9aad69f 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
| @@ -211,8 +211,9 @@ static int filter_pred_pchar(struct filter_pred *pred, void *event, | |||
| 211 | { | 211 | { |
| 212 | char **addr = (char **)(event + pred->offset); | 212 | char **addr = (char **)(event + pred->offset); |
| 213 | int cmp, match; | 213 | int cmp, match; |
| 214 | int len = strlen(*addr) + 1; /* including tailing '\0' */ | ||
| 214 | 215 | ||
| 215 | cmp = pred->regex.match(*addr, &pred->regex, pred->regex.field_len); | 216 | cmp = pred->regex.match(*addr, &pred->regex, len); |
| 216 | 217 | ||
| 217 | match = cmp ^ pred->not; | 218 | match = cmp ^ pred->not; |
| 218 | 219 | ||
| @@ -251,7 +252,18 @@ static int filter_pred_none(struct filter_pred *pred, void *event, | |||
| 251 | return 0; | 252 | return 0; |
| 252 | } | 253 | } |
| 253 | 254 | ||
| 254 | /* Basic regex callbacks */ | 255 | /* |
| 256 | * regex_match_foo - Basic regex callbacks | ||
| 257 | * | ||
| 258 | * @str: the string to be searched | ||
| 259 | * @r: the regex structure containing the pattern string | ||
| 260 | * @len: the length of the string to be searched (including '\0') | ||
| 261 | * | ||
| 262 | * Note: | ||
| 263 | * - @str might not be NULL-terminated if it's of type DYN_STRING | ||
| 264 | * or STATIC_STRING | ||
| 265 | */ | ||
| 266 | |||
| 255 | static int regex_match_full(char *str, struct regex *r, int len) | 267 | static int regex_match_full(char *str, struct regex *r, int len) |
| 256 | { | 268 | { |
| 257 | if (strncmp(str, r->pattern, len) == 0) | 269 | if (strncmp(str, r->pattern, len) == 0) |
| @@ -261,23 +273,24 @@ static int regex_match_full(char *str, struct regex *r, int len) | |||
| 261 | 273 | ||
| 262 | static int regex_match_front(char *str, struct regex *r, int len) | 274 | static int regex_match_front(char *str, struct regex *r, int len) |
| 263 | { | 275 | { |
| 264 | if (strncmp(str, r->pattern, len) == 0) | 276 | if (strncmp(str, r->pattern, r->len) == 0) |
| 265 | return 1; | 277 | return 1; |
| 266 | return 0; | 278 | return 0; |
| 267 | } | 279 | } |
| 268 | 280 | ||
| 269 | static int regex_match_middle(char *str, struct regex *r, int len) | 281 | static int regex_match_middle(char *str, struct regex *r, int len) |
| 270 | { | 282 | { |
| 271 | if (strstr(str, r->pattern)) | 283 | if (strnstr(str, r->pattern, len)) |
| 272 | return 1; | 284 | return 1; |
| 273 | return 0; | 285 | return 0; |
| 274 | } | 286 | } |
| 275 | 287 | ||
| 276 | static int regex_match_end(char *str, struct regex *r, int len) | 288 | static int regex_match_end(char *str, struct regex *r, int len) |
| 277 | { | 289 | { |
| 278 | char *ptr = strstr(str, r->pattern); | 290 | int strlen = len - 1; |
| 279 | 291 | ||
| 280 | if (ptr && (ptr[r->len] == 0)) | 292 | if (strlen >= r->len && |
| 293 | memcmp(str + strlen - r->len, r->pattern, r->len) == 0) | ||
| 281 | return 1; | 294 | return 1; |
| 282 | return 0; | 295 | return 0; |
| 283 | } | 296 | } |
| @@ -781,10 +794,8 @@ static int filter_add_pred(struct filter_parse_state *ps, | |||
| 781 | pred->regex.field_len = field->size; | 794 | pred->regex.field_len = field->size; |
| 782 | } else if (field->filter_type == FILTER_DYN_STRING) | 795 | } else if (field->filter_type == FILTER_DYN_STRING) |
| 783 | fn = filter_pred_strloc; | 796 | fn = filter_pred_strloc; |
| 784 | else { | 797 | else |
| 785 | fn = filter_pred_pchar; | 798 | fn = filter_pred_pchar; |
| 786 | pred->regex.field_len = strlen(pred->regex.pattern); | ||
| 787 | } | ||
| 788 | } else { | 799 | } else { |
| 789 | if (field->is_signed) | 800 | if (field->is_signed) |
| 790 | ret = strict_strtoll(pred->regex.pattern, 0, &val); | 801 | ret = strict_strtoll(pred->regex.pattern, 0, &val); |
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c index 6ea90c0e2c96..50b1b8239806 100644 --- a/kernel/trace/trace_kprobe.c +++ b/kernel/trace/trace_kprobe.c | |||
| @@ -689,7 +689,7 @@ static int create_trace_probe(int argc, char **argv) | |||
| 689 | return -EINVAL; | 689 | return -EINVAL; |
| 690 | } | 690 | } |
| 691 | /* an address specified */ | 691 | /* an address specified */ |
| 692 | ret = strict_strtoul(&argv[0][2], 0, (unsigned long *)&addr); | 692 | ret = strict_strtoul(&argv[1][0], 0, (unsigned long *)&addr); |
| 693 | if (ret) { | 693 | if (ret) { |
| 694 | pr_info("Failed to parse address.\n"); | 694 | pr_info("Failed to parse address.\n"); |
| 695 | return ret; | 695 | return ret; |
diff --git a/kernel/trace/trace_stack.c b/kernel/trace/trace_stack.c index 678a5120ee30..f4bc9b27de5f 100644 --- a/kernel/trace/trace_stack.c +++ b/kernel/trace/trace_stack.c | |||
| @@ -157,6 +157,7 @@ stack_max_size_write(struct file *filp, const char __user *ubuf, | |||
| 157 | unsigned long val, flags; | 157 | unsigned long val, flags; |
| 158 | char buf[64]; | 158 | char buf[64]; |
| 159 | int ret; | 159 | int ret; |
| 160 | int cpu; | ||
| 160 | 161 | ||
| 161 | if (count >= sizeof(buf)) | 162 | if (count >= sizeof(buf)) |
| 162 | return -EINVAL; | 163 | return -EINVAL; |
| @@ -171,9 +172,20 @@ stack_max_size_write(struct file *filp, const char __user *ubuf, | |||
| 171 | return ret; | 172 | return ret; |
| 172 | 173 | ||
| 173 | local_irq_save(flags); | 174 | local_irq_save(flags); |
| 175 | |||
| 176 | /* | ||
| 177 | * In case we trace inside arch_spin_lock() or after (NMI), | ||
| 178 | * we will cause circular lock, so we also need to increase | ||
| 179 | * the percpu trace_active here. | ||
| 180 | */ | ||
| 181 | cpu = smp_processor_id(); | ||
| 182 | per_cpu(trace_active, cpu)++; | ||
| 183 | |||
| 174 | arch_spin_lock(&max_stack_lock); | 184 | arch_spin_lock(&max_stack_lock); |
| 175 | *ptr = val; | 185 | *ptr = val; |
| 176 | arch_spin_unlock(&max_stack_lock); | 186 | arch_spin_unlock(&max_stack_lock); |
| 187 | |||
| 188 | per_cpu(trace_active, cpu)--; | ||
| 177 | local_irq_restore(flags); | 189 | local_irq_restore(flags); |
| 178 | 190 | ||
| 179 | return count; | 191 | return count; |
| @@ -206,7 +218,13 @@ t_next(struct seq_file *m, void *v, loff_t *pos) | |||
| 206 | 218 | ||
| 207 | static void *t_start(struct seq_file *m, loff_t *pos) | 219 | static void *t_start(struct seq_file *m, loff_t *pos) |
| 208 | { | 220 | { |
| 221 | int cpu; | ||
| 222 | |||
| 209 | local_irq_disable(); | 223 | local_irq_disable(); |
| 224 | |||
| 225 | cpu = smp_processor_id(); | ||
| 226 | per_cpu(trace_active, cpu)++; | ||
| 227 | |||
| 210 | arch_spin_lock(&max_stack_lock); | 228 | arch_spin_lock(&max_stack_lock); |
| 211 | 229 | ||
| 212 | if (*pos == 0) | 230 | if (*pos == 0) |
| @@ -217,7 +235,13 @@ static void *t_start(struct seq_file *m, loff_t *pos) | |||
| 217 | 235 | ||
| 218 | static void t_stop(struct seq_file *m, void *p) | 236 | static void t_stop(struct seq_file *m, void *p) |
| 219 | { | 237 | { |
| 238 | int cpu; | ||
| 239 | |||
| 220 | arch_spin_unlock(&max_stack_lock); | 240 | arch_spin_unlock(&max_stack_lock); |
| 241 | |||
| 242 | cpu = smp_processor_id(); | ||
| 243 | per_cpu(trace_active, cpu)--; | ||
| 244 | |||
| 221 | local_irq_enable(); | 245 | local_irq_enable(); |
| 222 | } | 246 | } |
| 223 | 247 | ||
