diff options
Diffstat (limited to 'kernel/trace/trace_uprobe.c')
-rw-r--r-- | kernel/trace/trace_uprobe.c | 51 |
1 files changed, 38 insertions, 13 deletions
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c index a23d2d71188e..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) { |
@@ -408,16 +419,20 @@ fail_address_parse: | |||
408 | return ret; | 419 | return ret; |
409 | } | 420 | } |
410 | 421 | ||
411 | static void cleanup_all_probes(void) | 422 | static int cleanup_all_probes(void) |
412 | { | 423 | { |
413 | struct trace_uprobe *tu; | 424 | struct trace_uprobe *tu; |
425 | int ret = 0; | ||
414 | 426 | ||
415 | mutex_lock(&uprobe_lock); | 427 | mutex_lock(&uprobe_lock); |
416 | while (!list_empty(&uprobe_list)) { | 428 | while (!list_empty(&uprobe_list)) { |
417 | tu = list_entry(uprobe_list.next, struct trace_uprobe, list); | 429 | tu = list_entry(uprobe_list.next, struct trace_uprobe, list); |
418 | unregister_trace_uprobe(tu); | 430 | ret = unregister_trace_uprobe(tu); |
431 | if (ret) | ||
432 | break; | ||
419 | } | 433 | } |
420 | mutex_unlock(&uprobe_lock); | 434 | mutex_unlock(&uprobe_lock); |
435 | return ret; | ||
421 | } | 436 | } |
422 | 437 | ||
423 | /* Probes listing interfaces */ | 438 | /* Probes listing interfaces */ |
@@ -462,8 +477,13 @@ static const struct seq_operations probes_seq_op = { | |||
462 | 477 | ||
463 | static int probes_open(struct inode *inode, struct file *file) | 478 | static int probes_open(struct inode *inode, struct file *file) |
464 | { | 479 | { |
465 | if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) | 480 | int ret; |
466 | 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 | } | ||
467 | 487 | ||
468 | return seq_open(file, &probes_seq_op); | 488 | return seq_open(file, &probes_seq_op); |
469 | } | 489 | } |
@@ -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 */ |