diff options
| -rw-r--r-- | fs/debugfs/inode.c | 69 | ||||
| -rw-r--r-- | include/linux/ftrace_event.h | 12 | ||||
| -rw-r--r-- | include/linux/kernel.h | 2 | ||||
| -rw-r--r-- | kernel/trace/ftrace.c | 87 | ||||
| -rw-r--r-- | kernel/trace/trace.c | 27 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 200 | ||||
| -rw-r--r-- | kernel/trace/trace_events_filter.c | 17 | ||||
| -rw-r--r-- | kernel/trace/trace_kprobe.c | 21 | ||||
| -rw-r--r-- | kernel/trace/trace_uprobe.c | 51 |
9 files changed, 302 insertions, 184 deletions
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c index 4888cb3fdef7..c7c83ff0f752 100644 --- a/fs/debugfs/inode.c +++ b/fs/debugfs/inode.c | |||
| @@ -533,8 +533,7 @@ EXPORT_SYMBOL_GPL(debugfs_remove); | |||
| 533 | */ | 533 | */ |
| 534 | void debugfs_remove_recursive(struct dentry *dentry) | 534 | void debugfs_remove_recursive(struct dentry *dentry) |
| 535 | { | 535 | { |
| 536 | struct dentry *child; | 536 | struct dentry *child, *next, *parent; |
| 537 | struct dentry *parent; | ||
| 538 | 537 | ||
| 539 | if (IS_ERR_OR_NULL(dentry)) | 538 | if (IS_ERR_OR_NULL(dentry)) |
| 540 | return; | 539 | return; |
| @@ -544,61 +543,37 @@ void debugfs_remove_recursive(struct dentry *dentry) | |||
| 544 | return; | 543 | return; |
| 545 | 544 | ||
| 546 | parent = dentry; | 545 | parent = dentry; |
| 546 | down: | ||
| 547 | mutex_lock(&parent->d_inode->i_mutex); | 547 | mutex_lock(&parent->d_inode->i_mutex); |
| 548 | list_for_each_entry_safe(child, next, &parent->d_subdirs, d_u.d_child) { | ||
| 549 | if (!debugfs_positive(child)) | ||
| 550 | continue; | ||
| 548 | 551 | ||
| 549 | while (1) { | 552 | /* perhaps simple_empty(child) makes more sense */ |
| 550 | /* | ||
| 551 | * When all dentries under "parent" has been removed, | ||
| 552 | * walk up the tree until we reach our starting point. | ||
| 553 | */ | ||
| 554 | if (list_empty(&parent->d_subdirs)) { | ||
| 555 | mutex_unlock(&parent->d_inode->i_mutex); | ||
| 556 | if (parent == dentry) | ||
| 557 | break; | ||
| 558 | parent = parent->d_parent; | ||
| 559 | mutex_lock(&parent->d_inode->i_mutex); | ||
| 560 | } | ||
| 561 | child = list_entry(parent->d_subdirs.next, struct dentry, | ||
| 562 | d_u.d_child); | ||
| 563 | next_sibling: | ||
| 564 | |||
| 565 | /* | ||
| 566 | * If "child" isn't empty, walk down the tree and | ||
| 567 | * remove all its descendants first. | ||
| 568 | */ | ||
| 569 | if (!list_empty(&child->d_subdirs)) { | 553 | if (!list_empty(&child->d_subdirs)) { |
| 570 | mutex_unlock(&parent->d_inode->i_mutex); | 554 | mutex_unlock(&parent->d_inode->i_mutex); |
| 571 | parent = child; | 555 | parent = child; |
| 572 | mutex_lock(&parent->d_inode->i_mutex); | 556 | goto down; |
| 573 | continue; | ||
| 574 | } | 557 | } |
| 575 | __debugfs_remove(child, parent); | 558 | up: |
| 576 | if (parent->d_subdirs.next == &child->d_u.d_child) { | 559 | if (!__debugfs_remove(child, parent)) |
| 577 | /* | 560 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); |
| 578 | * Try the next sibling. | ||
| 579 | */ | ||
| 580 | if (child->d_u.d_child.next != &parent->d_subdirs) { | ||
| 581 | child = list_entry(child->d_u.d_child.next, | ||
| 582 | struct dentry, | ||
| 583 | d_u.d_child); | ||
| 584 | goto next_sibling; | ||
| 585 | } | ||
| 586 | |||
| 587 | /* | ||
| 588 | * Avoid infinite loop if we fail to remove | ||
| 589 | * one dentry. | ||
| 590 | */ | ||
| 591 | mutex_unlock(&parent->d_inode->i_mutex); | ||
| 592 | break; | ||
| 593 | } | ||
| 594 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | ||
| 595 | } | 561 | } |
| 596 | 562 | ||
| 597 | parent = dentry->d_parent; | 563 | mutex_unlock(&parent->d_inode->i_mutex); |
| 564 | child = parent; | ||
| 565 | parent = parent->d_parent; | ||
| 598 | mutex_lock(&parent->d_inode->i_mutex); | 566 | mutex_lock(&parent->d_inode->i_mutex); |
| 599 | __debugfs_remove(dentry, parent); | 567 | |
| 568 | if (child != dentry) { | ||
| 569 | next = list_entry(child->d_u.d_child.next, struct dentry, | ||
| 570 | d_u.d_child); | ||
| 571 | goto up; | ||
| 572 | } | ||
| 573 | |||
| 574 | if (!__debugfs_remove(child, parent)) | ||
| 575 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | ||
| 600 | mutex_unlock(&parent->d_inode->i_mutex); | 576 | mutex_unlock(&parent->d_inode->i_mutex); |
| 601 | simple_release_fs(&debugfs_mount, &debugfs_mount_count); | ||
| 602 | } | 577 | } |
| 603 | EXPORT_SYMBOL_GPL(debugfs_remove_recursive); | 578 | EXPORT_SYMBOL_GPL(debugfs_remove_recursive); |
| 604 | 579 | ||
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index 4372658c73ae..120d57a1c3a5 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
| @@ -78,6 +78,11 @@ struct trace_iterator { | |||
| 78 | /* trace_seq for __print_flags() and __print_symbolic() etc. */ | 78 | /* trace_seq for __print_flags() and __print_symbolic() etc. */ |
| 79 | struct trace_seq tmp_seq; | 79 | struct trace_seq tmp_seq; |
| 80 | 80 | ||
| 81 | cpumask_var_t started; | ||
| 82 | |||
| 83 | /* it's true when current open file is snapshot */ | ||
| 84 | bool snapshot; | ||
| 85 | |||
| 81 | /* The below is zeroed out in pipe_read */ | 86 | /* The below is zeroed out in pipe_read */ |
| 82 | struct trace_seq seq; | 87 | struct trace_seq seq; |
| 83 | struct trace_entry *ent; | 88 | struct trace_entry *ent; |
| @@ -90,10 +95,7 @@ struct trace_iterator { | |||
| 90 | loff_t pos; | 95 | loff_t pos; |
| 91 | long idx; | 96 | long idx; |
| 92 | 97 | ||
| 93 | cpumask_var_t started; | 98 | /* All new field here will be zeroed out in pipe_read */ |
| 94 | |||
| 95 | /* it's true when current open file is snapshot */ | ||
| 96 | bool snapshot; | ||
| 97 | }; | 99 | }; |
| 98 | 100 | ||
| 99 | enum trace_iter_flags { | 101 | enum trace_iter_flags { |
| @@ -332,7 +334,7 @@ extern int trace_define_field(struct ftrace_event_call *call, const char *type, | |||
| 332 | const char *name, int offset, int size, | 334 | const char *name, int offset, int size, |
| 333 | int is_signed, int filter_type); | 335 | int is_signed, int filter_type); |
| 334 | extern int trace_add_event_call(struct ftrace_event_call *call); | 336 | extern int trace_add_event_call(struct ftrace_event_call *call); |
| 335 | extern void trace_remove_event_call(struct ftrace_event_call *call); | 337 | extern int trace_remove_event_call(struct ftrace_event_call *call); |
| 336 | 338 | ||
| 337 | #define is_signed_type(type) (((type)(-1)) < (type)1) | 339 | #define is_signed_type(type) (((type)(-1)) < (type)1) |
| 338 | 340 | ||
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 3bef14c6586b..482ad2d84a32 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
| @@ -629,7 +629,7 @@ extern void ftrace_dump(enum ftrace_dump_mode oops_dump_mode); | |||
| 629 | static inline void tracing_start(void) { } | 629 | static inline void tracing_start(void) { } |
| 630 | static inline void tracing_stop(void) { } | 630 | static inline void tracing_stop(void) { } |
| 631 | static inline void ftrace_off_permanent(void) { } | 631 | static inline void ftrace_off_permanent(void) { } |
| 632 | static inline void trace_dump_stack(void) { } | 632 | static inline void trace_dump_stack(int skip) { } |
| 633 | 633 | ||
| 634 | static inline void tracing_on(void) { } | 634 | static inline void tracing_on(void) { } |
| 635 | static inline void tracing_off(void) { } | 635 | static inline void tracing_off(void) { } |
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 8ce9eefc5bb4..a6d098c6df3f 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
| @@ -2169,12 +2169,57 @@ static cycle_t ftrace_update_time; | |||
| 2169 | static unsigned long ftrace_update_cnt; | 2169 | static unsigned long ftrace_update_cnt; |
| 2170 | unsigned long ftrace_update_tot_cnt; | 2170 | unsigned long ftrace_update_tot_cnt; |
| 2171 | 2171 | ||
| 2172 | static int ops_traces_mod(struct ftrace_ops *ops) | 2172 | static inline int ops_traces_mod(struct ftrace_ops *ops) |
| 2173 | { | 2173 | { |
| 2174 | struct ftrace_hash *hash; | 2174 | /* |
| 2175 | * Filter_hash being empty will default to trace module. | ||
| 2176 | * But notrace hash requires a test of individual module functions. | ||
| 2177 | */ | ||
| 2178 | return ftrace_hash_empty(ops->filter_hash) && | ||
| 2179 | ftrace_hash_empty(ops->notrace_hash); | ||
| 2180 | } | ||
| 2181 | |||
| 2182 | /* | ||
| 2183 | * Check if the current ops references the record. | ||
| 2184 | * | ||
| 2185 | * If the ops traces all functions, then it was already accounted for. | ||
| 2186 | * If the ops does not trace the current record function, skip it. | ||
| 2187 | * If the ops ignores the function via notrace filter, skip it. | ||
| 2188 | */ | ||
| 2189 | static inline bool | ||
| 2190 | ops_references_rec(struct ftrace_ops *ops, struct dyn_ftrace *rec) | ||
| 2191 | { | ||
| 2192 | /* If ops isn't enabled, ignore it */ | ||
| 2193 | if (!(ops->flags & FTRACE_OPS_FL_ENABLED)) | <||
