diff options
Diffstat (limited to 'kernel/trace/trace_uprobe.c')
| -rw-r--r-- | kernel/trace/trace_uprobe.c | 57 |
1 files changed, 41 insertions, 16 deletions
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index 32494fb0ee64..272261b5f94f 100644 --- a/kernel/trace/trace_uprobe.c +++ b/kernel/trace/trace_uprobe.c | |||
| @@ -70,7 +70,7 @@ struct trace_uprobe { | |||
| 70 | (sizeof(struct probe_arg) * (n))) | 70 | (sizeof(struct probe_arg) * (n))) |
| 71 | 71 | ||
| 72 | static int register_uprobe_event(struct trace_uprobe *tu); | 72 | static int register_uprobe_event(struct trace_uprobe *tu); |
| 73 | static void unregister_uprobe_event(struct trace_uprobe *tu); | 73 | static int unregister_uprobe_event(struct trace_uprobe *tu); |
| 74 | 74 | ||
| 75 | static DEFINE_MUTEX(uprobe_lock); | 75 | static DEFINE_MUTEX(uprobe_lock); |
| 76 | static LIST_HEAD(uprobe_list); | 76 | static LIST_HEAD(uprobe_list); |
| @@ -164,11 +164,17 @@ static struct trace_uprobe *find_probe_event(const char *event, const char *grou | |||
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | /* Unregister a trace_uprobe and probe_event: call with locking uprobe_lock */ | 166 | /* Unregister a trace_uprobe and probe_event: call with locking uprobe_lock */ |
| 167 | static void unregister_trace_uprobe(struct trace_uprobe *tu) | 167 | static int unregister_trace_uprobe(struct trace_uprobe *tu) |
| 168 | { | 168 | { |
| 169 | int ret; | ||
| 170 | |||
| 171 | ret = unregister_uprobe_event(tu); | ||
| 172 | if (ret) | ||
| 173 | return ret; | ||
| 174 | |||
| 169 | list_del(&tu->list); | 175 | list_del(&tu->list); |
| 170 | unregister_uprobe_event(tu); | ||
| 171 | free_trace_uprobe(tu); | 176 | free_trace_uprobe(tu); |
| 177 | return 0; | ||
| 172 | } | 178 | } |
| 173 | 179 | ||
| 174 | /* Register a trace_uprobe and probe_event */ | 180 | /* Register a trace_uprobe and probe_event */ |
| @@ -181,9 +187,12 @@ static int register_trace_uprobe(struct trace_uprobe *tu) | |||
| 181 | 187 | ||
| 182 | /* register as an event */ | 188 | /* register as an event */ |
| 183 | old_tp = find_probe_event(tu->call.name, tu->call.class->system); | 189 | old_tp = find_probe_event(tu->call.name, tu->call.class->system); |
| 184 | if (old_tp) | 190 | if (old_tp) { |
| 185 | /* delete old event */ | 191 | /* delete old event */ |
| 186 | unregister_trace_uprobe(old_tp); | 192 | ret = unregister_trace_uprobe(old_tp); |
| 193 | if (ret) | ||
| 194 | goto end; | ||
| 195 | } | ||
| 187 | 196 | ||
| 188 | ret = register_uprobe_event(tu); | 197 | ret = register_uprobe_event(tu); |
| 189 | if (ret) { | 198 | if (ret) { |
| @@ -256,6 +265,8 @@ static int create_trace_uprobe(int argc, char **argv) | |||
| 256 | group = UPROBE_EVENT_SYSTEM; | 265 | group = UPROBE_EVENT_SYSTEM; |
| 257 | 266 | ||
| 258 | if (is_delete) { | 267 | if (is_delete) { |
| 268 | int ret; | ||
| 269 | |||
| 259 | if (!event) { | 270 | if (!event) { |
| 260 | pr_info("Delete command needs an event name.\n"); | 271 | pr_info("Delete command needs an event name.\n"); |
| 261 | return -EINVAL; | 272 | return -EINVAL; |
| @@ -269,9 +280,9 @@ static int create_trace_uprobe(int argc, char **argv) | |||
| 269 | return -ENOENT; | 280 | return -ENOENT; |
| 270 | } | 281 | } |
| 271 | /* delete an event */ | 282 | /* delete an event */ |
| 272 | unregister_trace_uprobe(tu); | 283 | ret = unregister_trace_uprobe(tu); |
| 273 | mutex_unlock(&uprobe_lock); | 284 | mutex_unlock(&uprobe_lock); |
| 274 | return 0; | 285 | return ret; |
| 275 | } | 286 | } |
| 276 | 287 | ||
| 277 | if (argc < 2) { | 288 | if (argc < 2) { |
| @@ -283,8 +294,10 @@ static int create_trace_uprobe(int argc, char **argv) | |||
| 283 | return -EINVAL; | 294 | return -EINVAL; |
| 284 | } | 295 | } |
| 285 | arg = strchr(argv[1], ':'); | 296 | arg = strchr(argv[1], ':'); |
| 286 | if (!arg) | 297 | if (!arg) { |
| 298 | ret = -EINVAL; | ||
| 287 | goto fail_address_parse; | 299 | goto fail_address_parse; |
| 300 | } | ||
| 288 | 301 | ||
| 289 | *arg++ = '\0'; | 302 | *arg++ = '\0'; |
| 290 | filename = argv[1]; | 303 | filename = argv[1]; |
| @@ -406,16 +419,20 @@ fail_address_parse: | |||
| 406 | return ret; | 419 | return ret; |
| 407 | } | 420 | } |
| 408 | 421 | ||
| 409 | static void cleanup_all_probes(void) | 422 | static int cleanup_all_probes(void) |
| 410 | { | 423 | { |
| 411 | struct trace_uprobe *tu; | 424 | struct trace_uprobe *tu; |
| 425 | int ret = 0; | ||
| 412 | 426 | ||
| 413 | mutex_lock(&uprobe_lock); | 427 | mutex_lock(&uprobe_lock); |
| 414 | while (!list_empty(&uprobe_list)) { | 428 | while (!list_empty(&uprobe_list)) { |
| 415 | tu = list_entry(uprobe_list.next, struct trace_uprobe, list); | 429 | tu = list_entry(uprobe_list.next, struct trace_uprobe, list); |
| 416 | unregister_trace_uprobe(tu); | 430 | ret = unregister_trace_uprobe(tu); |
| 431 | if (ret) | ||
| 432 | break; | ||
| 417 | } | 433 | } |
| 418 | mutex_unlock(&uprobe_lock); | 434 | mutex_unlock(&uprobe_lock); |
| 435 | return ret; | ||
| 419 | } | 436 | } |
| 420 | 437 | ||
| 421 | /* Probes listing interfaces */ | 438 | /* Probes listing interfaces */ |
| @@ -460,8 +477,13 @@ static const struct seq_operations probes_seq_op = { | |||
| 460 | 477 | ||
| 461 | static int probes_open(struct inode *inode, struct file *file) | 478 | static int probes_open(struct inode *inode, struct file *file) |
| 462 | { | 479 | { |
| 463 | if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) | 480 | int ret; |
| 464 | cleanup_all_probes(); | 481 | |
| 482 | if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) { | ||
| 483 | ret = cleanup_all_probes(); | ||
| 484 | if (ret) | ||
| 485 | return ret; | ||
| 486 | } | ||
| 465 | 487 | ||
| 466 | return seq_open(file, &probes_seq_op); | 488 | return seq_open(file, &probes_seq_op); |
| 467 | } | 489 | } |
| @@ -816,8 +838,6 @@ static void uprobe_perf_print(struct trace_uprobe *tu, | |||
| 816 | 838 | ||
| 817 | size = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); | 839 | size = SIZEOF_TRACE_ENTRY(is_ret_probe(tu)); |
| 818 | size = ALIGN(size + tu->size + sizeof(u32), sizeof(u64)) - sizeof(u32); | 840 | size = ALIGN(size + tu->size + sizeof(u32), sizeof(u64)) - sizeof(u32); |
| 819 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, "profile buffer not large enough")) | ||
| 820 | return; | ||
| 821 | 841 | ||
| 822 | preempt_disable(); | 842 | preempt_disable(); |
| 823 | head = this_cpu_ptr(call->perf_events); | 843 | head = this_cpu_ptr(call->perf_events); |
| @@ -968,12 +988,17 @@ static int register_uprobe_event(struct trace_uprobe *tu) | |||
| 968 | return ret; | 988 | return ret; |
| 969 | } | 989 | } |
| 970 | 990 | ||
| 971 | static void unregister_uprobe_event(struct trace_uprobe *tu) | 991 | static int unregister_uprobe_event(struct trace_uprobe *tu) |
| 972 | { | 992 | { |
| 993 | int ret; | ||
| 994 | |||
| 973 | /* tu->event is unregistered in trace_remove_event_call() */ | 995 | /* tu->event is unregistered in trace_remove_event_call() */ |
| 974 | trace_remove_event_call(&tu->call); | 996 | ret = trace_remove_event_call(&tu->call); |
| 997 | if (ret) | ||
| 998 | return ret; | ||
| 975 | kfree(tu->call.print_fmt); | 999 | kfree(tu->call.print_fmt); |
| 976 | tu->call.print_fmt = NULL; | 1000 | tu->call.print_fmt = NULL; |
| 1001 | return 0; | ||
| 977 | } | 1002 | } |
| 978 | 1003 | ||
| 979 | /* Make a trace interface for controling probe points */ | 1004 | /* Make a trace interface for controling probe points */ |
