diff options
Diffstat (limited to 'include/linux')
-rw-r--r-- | include/linux/ftrace.h | 77 | ||||
-rw-r--r-- | include/linux/ftrace_event.h | 9 | ||||
-rw-r--r-- | include/linux/interrupt.h | 7 | ||||
-rw-r--r-- | include/linux/jump_label.h | 162 | ||||
-rw-r--r-- | include/linux/netdevice.h | 4 | ||||
-rw-r--r-- | include/linux/netfilter.h | 6 | ||||
-rw-r--r-- | include/linux/perf_event.h | 26 | ||||
-rw-r--r-- | include/linux/static_key.h | 1 | ||||
-rw-r--r-- | include/linux/tracepoint.h | 28 |
9 files changed, 253 insertions, 67 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 028e26f0bf08..72a6cabb4d5b 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -31,16 +31,33 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, | |||
31 | 31 | ||
32 | typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip); | 32 | typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip); |
33 | 33 | ||
34 | /* | ||
35 | * FTRACE_OPS_FL_* bits denote the state of ftrace_ops struct and are | ||
36 | * set in the flags member. | ||
37 | * | ||
38 | * ENABLED - set/unset when ftrace_ops is registered/unregistered | ||
39 | * GLOBAL - set manualy by ftrace_ops user to denote the ftrace_ops | ||
40 | * is part of the global tracers sharing the same filter | ||
41 | * via set_ftrace_* debugfs files. | ||
42 | * DYNAMIC - set when ftrace_ops is registered to denote dynamically | ||
43 | * allocated ftrace_ops which need special care | ||
44 | * CONTROL - set manualy by ftrace_ops user to denote the ftrace_ops | ||
45 | * could be controled by following calls: | ||
46 | * ftrace_function_local_enable | ||
47 | * ftrace_function_local_disable | ||
48 | */ | ||
34 | enum { | 49 | enum { |
35 | FTRACE_OPS_FL_ENABLED = 1 << 0, | 50 | FTRACE_OPS_FL_ENABLED = 1 << 0, |
36 | FTRACE_OPS_FL_GLOBAL = 1 << 1, | 51 | FTRACE_OPS_FL_GLOBAL = 1 << 1, |
37 | FTRACE_OPS_FL_DYNAMIC = 1 << 2, | 52 | FTRACE_OPS_FL_DYNAMIC = 1 << 2, |
53 | FTRACE_OPS_FL_CONTROL = 1 << 3, | ||
38 | }; | 54 | }; |
39 | 55 | ||
40 | struct ftrace_ops { | 56 | struct ftrace_ops { |
41 | ftrace_func_t func; | 57 | ftrace_func_t func; |
42 | struct ftrace_ops *next; | 58 | struct ftrace_ops *next; |
43 | unsigned long flags; | 59 | unsigned long flags; |
60 | int __percpu *disabled; | ||
44 | #ifdef CONFIG_DYNAMIC_FTRACE | 61 | #ifdef CONFIG_DYNAMIC_FTRACE |
45 | struct ftrace_hash *notrace_hash; | 62 | struct ftrace_hash *notrace_hash; |
46 | struct ftrace_hash *filter_hash; | 63 | struct ftrace_hash *filter_hash; |
@@ -97,6 +114,55 @@ int register_ftrace_function(struct ftrace_ops *ops); | |||
97 | int unregister_ftrace_function(struct ftrace_ops *ops); | 114 | int unregister_ftrace_function(struct ftrace_ops *ops); |
98 | void clear_ftrace_function(void); | 115 | void clear_ftrace_function(void); |
99 | 116 | ||
117 | /** | ||
118 | * ftrace_function_local_enable - enable controlled ftrace_ops on current cpu | ||
119 | * | ||
120 | * This function enables tracing on current cpu by decreasing | ||
121 | * the per cpu control variable. | ||
122 | * It must be called with preemption disabled and only on ftrace_ops | ||
123 | * registered with FTRACE_OPS_FL_CONTROL. If called without preemption | ||
124 | * disabled, this_cpu_ptr will complain when CONFIG_DEBUG_PREEMPT is enabled. | ||
125 | */ | ||
126 | static inline void ftrace_function_local_enable(struct ftrace_ops *ops) | ||
127 | { | ||
128 | if (WARN_ON_ONCE(!(ops->flags & FTRACE_OPS_FL_CONTROL))) | ||
129 | return; | ||
130 | |||
131 | (*this_cpu_ptr(ops->disabled))--; | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * ftrace_function_local_disable - enable controlled ftrace_ops on current cpu | ||
136 | * | ||
137 | * This function enables tracing on current cpu by decreasing | ||
138 | * the per cpu control variable. | ||
139 | * It must be called with preemption disabled and only on ftrace_ops | ||
140 | * registered with FTRACE_OPS_FL_CONTROL. If called without preemption | ||
141 | * disabled, this_cpu_ptr will complain when CONFIG_DEBUG_PREEMPT is enabled. | ||
142 | */ | ||
143 | static inline void ftrace_function_local_disable(struct ftrace_ops *ops) | ||
144 | { | ||
145 | if (WARN_ON_ONCE(!(ops->flags & FTRACE_OPS_FL_CONTROL))) | ||
146 | return; | ||
147 | |||
148 | (*this_cpu_ptr(ops->disabled))++; | ||
149 | } | ||
150 | |||
151 | /** | ||
152 | * ftrace_function_local_disabled - returns ftrace_ops disabled value | ||
153 | * on current cpu | ||
154 | * | ||
155 | * This function returns value of ftrace_ops::disabled on current cpu. | ||
156 | * It must be called with preemption disabled and only on ftrace_ops | ||
157 | * registered with FTRACE_OPS_FL_CONTROL. If called without preemption | ||
158 | * disabled, this_cpu_ptr will complain when CONFIG_DEBUG_PREEMPT is enabled. | ||
159 | */ | ||
160 | static inline int ftrace_function_local_disabled(struct ftrace_ops *ops) | ||
161 | { | ||
162 | WARN_ON_ONCE(!(ops->flags & FTRACE_OPS_FL_CONTROL)); | ||
163 | return *this_cpu_ptr(ops->disabled); | ||
164 | } | ||
165 | |||
100 | extern void ftrace_stub(unsigned long a0, unsigned long a1); | 166 | extern void ftrace_stub(unsigned long a0, unsigned long a1); |
101 | 167 | ||
102 | #else /* !CONFIG_FUNCTION_TRACER */ | 168 | #else /* !CONFIG_FUNCTION_TRACER */ |
@@ -178,12 +244,13 @@ struct dyn_ftrace { | |||
178 | }; | 244 | }; |
179 | 245 | ||
180 | int ftrace_force_update(void); | 246 | int ftrace_force_update(void); |
181 | void ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf, | 247 | int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf, |
182 | int len, int reset); | 248 | int len, int reset); |
183 | void ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, | 249 | int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, |
184 | int len, int reset); | 250 | int len, int reset); |
185 | void ftrace_set_global_filter(unsigned char *buf, int len, int reset); | 251 | void ftrace_set_global_filter(unsigned char *buf, int len, int reset); |
186 | void ftrace_set_global_notrace(unsigned char *buf, int len, int reset); | 252 | void ftrace_set_global_notrace(unsigned char *buf, int len, int reset); |
253 | void ftrace_free_filter(struct ftrace_ops *ops); | ||
187 | 254 | ||
188 | int register_ftrace_command(struct ftrace_func_command *cmd); | 255 | int register_ftrace_command(struct ftrace_func_command *cmd); |
189 | int unregister_ftrace_command(struct ftrace_func_command *cmd); | 256 | int unregister_ftrace_command(struct ftrace_func_command *cmd); |
@@ -314,9 +381,6 @@ extern void ftrace_enable_daemon(void); | |||
314 | #else | 381 | #else |
315 | static inline int skip_trace(unsigned long ip) { return 0; } | 382 | static inline int skip_trace(unsigned long ip) { return 0; } |
316 | static inline int ftrace_force_update(void) { return 0; } | 383 | static inline int ftrace_force_update(void) { return 0; } |
317 | static inline void ftrace_set_filter(unsigned char *buf, int len, int reset) | ||
318 | { | ||
319 | } | ||
320 | static inline void ftrace_disable_daemon(void) { } | 384 | static inline void ftrace_disable_daemon(void) { } |
321 | static inline void ftrace_enable_daemon(void) { } | 385 | static inline void ftrace_enable_daemon(void) { } |
322 | static inline void ftrace_release_mod(struct module *mod) {} | 386 | static inline void ftrace_release_mod(struct module *mod) {} |
@@ -340,6 +404,9 @@ static inline int ftrace_text_reserved(void *start, void *end) | |||
340 | */ | 404 | */ |
341 | #define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; }) | 405 | #define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; }) |
342 | #define ftrace_set_early_filter(ops, buf, enable) do { } while (0) | 406 | #define ftrace_set_early_filter(ops, buf, enable) do { } while (0) |
407 | #define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; }) | ||
408 | #define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; }) | ||
409 | #define ftrace_free_filter(ops) do { } while (0) | ||
343 | 410 | ||
344 | static inline ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf, | 411 | static inline ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf, |
345 | size_t cnt, loff_t *ppos) { return -ENODEV; } | 412 | size_t cnt, loff_t *ppos) { return -ENODEV; } |
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index c3da42dd22ba..dd478fc8f9f5 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
@@ -146,6 +146,10 @@ enum trace_reg { | |||
146 | TRACE_REG_UNREGISTER, | 146 | TRACE_REG_UNREGISTER, |
147 | TRACE_REG_PERF_REGISTER, | 147 | TRACE_REG_PERF_REGISTER, |
148 | TRACE_REG_PERF_UNREGISTER, | 148 | TRACE_REG_PERF_UNREGISTER, |
149 | TRACE_REG_PERF_OPEN, | ||
150 | TRACE_REG_PERF_CLOSE, | ||
151 | TRACE_REG_PERF_ADD, | ||
152 | TRACE_REG_PERF_DEL, | ||
149 | }; | 153 | }; |
150 | 154 | ||
151 | struct ftrace_event_call; | 155 | struct ftrace_event_call; |
@@ -157,7 +161,7 @@ struct ftrace_event_class { | |||
157 | void *perf_probe; | 161 | void *perf_probe; |
158 | #endif | 162 | #endif |
159 | int (*reg)(struct ftrace_event_call *event, | 163 | int (*reg)(struct ftrace_event_call *event, |
160 | enum trace_reg type); | 164 | enum trace_reg type, void *data); |
161 | int (*define_fields)(struct ftrace_event_call *); | 165 | int (*define_fields)(struct ftrace_event_call *); |
162 | struct list_head *(*get_fields)(struct ftrace_event_call *); | 166 | struct list_head *(*get_fields)(struct ftrace_event_call *); |
163 | struct list_head fields; | 167 | struct list_head fields; |
@@ -165,7 +169,7 @@ struct ftrace_event_class { | |||
165 | }; | 169 | }; |
166 | 170 | ||
167 | extern int ftrace_event_reg(struct ftrace_event_call *event, | 171 | extern int ftrace_event_reg(struct ftrace_event_call *event, |
168 | enum trace_reg type); | 172 | enum trace_reg type, void *data); |
169 | 173 | ||
170 | enum { | 174 | enum { |
171 | TRACE_EVENT_FL_ENABLED_BIT, | 175 | TRACE_EVENT_FL_ENABLED_BIT, |
@@ -241,6 +245,7 @@ enum { | |||
241 | FILTER_STATIC_STRING, | 245 | FILTER_STATIC_STRING, |
242 | FILTER_DYN_STRING, | 246 | FILTER_DYN_STRING, |
243 | FILTER_PTR_STRING, | 247 | FILTER_PTR_STRING, |
248 | FILTER_TRACE_FN, | ||
244 | }; | 249 | }; |
245 | 250 | ||
246 | #define EVENT_STORAGE_SIZE 128 | 251 | #define EVENT_STORAGE_SIZE 128 |
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index a64b00e286f5..3f830e005118 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h | |||
@@ -20,7 +20,6 @@ | |||
20 | #include <linux/atomic.h> | 20 | #include <linux/atomic.h> |
21 | #include <asm/ptrace.h> | 21 | #include <asm/ptrace.h> |
22 | #include <asm/system.h> | 22 | #include <asm/system.h> |
23 | #include <trace/events/irq.h> | ||
24 | 23 | ||
25 | /* | 24 | /* |
26 | * These correspond to the IORESOURCE_IRQ_* defines in | 25 | * These correspond to the IORESOURCE_IRQ_* defines in |
@@ -456,11 +455,7 @@ asmlinkage void do_softirq(void); | |||
456 | asmlinkage void __do_softirq(void); | 455 | asmlinkage void __do_softirq(void); |
457 | extern void open_softirq(int nr, void (*action)(struct softirq_action *)); | 456 | extern void open_softirq(int nr, void (*action)(struct softirq_action *)); |
458 | extern void softirq_init(void); | 457 | extern void softirq_init(void); |
459 | static inline void __raise_softirq_irqoff(unsigned int nr) | 458 | extern void __raise_softirq_irqoff(unsigned int nr); |
460 | { | ||
461 | trace_softirq_raise(nr); | ||
462 | or_softirq_pending(1UL << nr); | ||
463 | } | ||
464 | 459 | ||
465 | extern void raise_softirq_irqoff(unsigned int nr); | 460 | extern void raise_softirq_irqoff(unsigned int nr); |
466 | extern void raise_softirq(unsigned int nr); | 461 | extern void raise_softirq(unsigned int nr); |
diff --git a/include/linux/jump_label.h b/include/linux/jump_label.h index 5ce8b140428f..c513a40510f5 100644 --- a/include/linux/jump_label.h +++ b/include/linux/jump_label.h | |||
@@ -1,22 +1,69 @@ | |||
1 | #ifndef _LINUX_JUMP_LABEL_H | 1 | #ifndef _LINUX_JUMP_LABEL_H |
2 | #define _LINUX_JUMP_LABEL_H | 2 | #define _LINUX_JUMP_LABEL_H |
3 | 3 | ||
4 | /* | ||
5 | * Jump label support | ||
6 | * | ||
7 | * Copyright (C) 2009-2012 Jason Baron <jbaron@redhat.com> | ||
8 | * Copyright (C) 2011-2012 Peter Zijlstra <pzijlstr@redhat.com> | ||
9 | * | ||
10 | * Jump labels provide an interface to generate dynamic branches using | ||
11 | * self-modifying code. Assuming toolchain and architecture support the result | ||
12 | * of a "if (static_key_false(&key))" statement is a unconditional branch (which | ||
13 | * defaults to false - and the true block is placed out of line). | ||
14 | * | ||
15 | * However at runtime we can change the branch target using | ||
16 | * static_key_slow_{inc,dec}(). These function as a 'reference' count on the key | ||
17 | * object and for as long as there are references all branches referring to | ||
18 | * that particular key will point to the (out of line) true block. | ||
19 | * | ||
20 | * Since this relies on modifying code the static_key_slow_{inc,dec}() functions | ||
21 | * must be considered absolute slow paths (machine wide synchronization etc.). | ||
22 | * OTOH, since the affected branches are unconditional their runtime overhead | ||
23 | * will be absolutely minimal, esp. in the default (off) case where the total | ||
24 | * effect is a single NOP of appropriate size. The on case will patch in a jump | ||
25 | * to the out-of-line block. | ||
26 | * | ||
27 | * When the control is directly exposed to userspace it is prudent to delay the | ||
28 | * decrement to avoid high frequency code modifications which can (and do) | ||
29 | * cause significant performance degradation. Struct static_key_deferred and | ||
30 | * static_key_slow_dec_deferred() provide for this. | ||
31 | * | ||
32 | * Lacking toolchain and or architecture support, it falls back to a simple | ||
33 | * conditional branch. | ||
34 | * | ||
35 | * struct static_key my_key = STATIC_KEY_INIT_TRUE; | ||
36 | * | ||
37 | * if (static_key_true(&my_key)) { | ||
38 | * } | ||
39 | * | ||
40 | * will result in the true case being in-line and starts the key with a single | ||
41 | * reference. Mixing static_key_true() and static_key_false() on the same key is not | ||
42 | * allowed. | ||
43 | * | ||
44 | * Not initializing the key (static data is initialized to 0s anyway) is the | ||
45 | * same as using STATIC_KEY_INIT_FALSE and static_key_false() is | ||
46 | * equivalent with static_branch(). | ||
47 | * | ||
48 | */ | ||
49 | |||
4 | #include <linux/types.h> | 50 | #include <linux/types.h> |
5 | #include <linux/compiler.h> | 51 | #include <linux/compiler.h> |
6 | #include <linux/workqueue.h> | 52 | #include <linux/workqueue.h> |
7 | 53 | ||
8 | #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL) | 54 | #if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL) |
9 | 55 | ||
10 | struct jump_label_key { | 56 | struct static_key { |
11 | atomic_t enabled; | 57 | atomic_t enabled; |
58 | /* Set lsb bit to 1 if branch is default true, 0 ot */ | ||
12 | struct jump_entry *entries; | 59 | struct jump_entry *entries; |
13 | #ifdef CONFIG_MODULES | 60 | #ifdef CONFIG_MODULES |
14 | struct jump_label_mod *next; | 61 | struct static_key_mod *next; |
15 | #endif | 62 | #endif |
16 | }; | 63 | }; |
17 | 64 | ||
18 | struct jump_label_key_deferred { | 65 | struct static_key_deferred { |
19 | struct jump_label_key key; | 66 | struct static_key key; |
20 | unsigned long timeout; | 67 | unsigned long timeout; |
21 | struct delayed_work work; | 68 | struct delayed_work work; |
22 | }; | 69 | }; |
@@ -34,13 +81,34 @@ struct module; | |||
34 | 81 | ||
35 | #ifdef HAVE_JUMP_LABEL | 82 | #ifdef HAVE_JUMP_LABEL |
36 | 83 | ||
37 | #ifdef CONFIG_MODULES | 84 | #define JUMP_LABEL_TRUE_BRANCH 1UL |
38 | #define JUMP_LABEL_INIT {ATOMIC_INIT(0), NULL, NULL} | 85 | |
39 | #else | 86 | static |
40 | #define JUMP_LABEL_INIT {ATOMIC_INIT(0), NULL} | 87 | inline struct jump_entry *jump_label_get_entries(struct static_key *key) |
41 | #endif | 88 | { |
89 | return (struct jump_entry *)((unsigned long)key->entries | ||
90 | & ~JUMP_LABEL_TRUE_BRANCH); | ||
91 | } | ||
42 | 92 | ||
43 | static __always_inline bool static_branch(struct jump_label_key *key) | 93 | static inline bool jump_label_get_branch_default(struct static_key *key) |
94 | { | ||
95 | if ((unsigned long)key->entries & JUMP_LABEL_TRUE_BRANCH) | ||
96 | return true; | ||
97 | return false; | ||
98 | } | ||
99 | |||
100 | static __always_inline bool static_key_false(struct static_key *key) | ||
101 | { | ||
102 | return arch_static_branch(key); | ||
103 | } | ||
104 | |||
105 | static __always_inline bool static_key_true(struct static_key *key) | ||
106 | { | ||
107 | return !static_key_false(key); | ||
108 | } | ||
109 | |||
110 | /* Deprecated. Please use 'static_key_false() instead. */ | ||
111 | static __always_inline bool static_branch(struct static_key *key) | ||
44 | { | 112 | { |
45 | return arch_static_branch(key); | 113 | return arch_static_branch(key); |
46 | } | 114 | } |
@@ -56,21 +124,23 @@ extern void arch_jump_label_transform(struct jump_entry *entry, | |||
56 | extern void arch_jump_label_transform_static(struct jump_entry *entry, | 124 | extern void arch_jump_label_transform_static(struct jump_entry *entry, |
57 | enum jump_label_type type); | 125 | enum jump_label_type type); |
58 | extern int jump_label_text_reserved(void *start, void *end); | 126 | extern int jump_label_text_reserved(void *start, void *end); |
59 | extern void jump_label_inc(struct jump_label_key *key); | 127 | extern void static_key_slow_inc(struct static_key *key); |
60 | extern void jump_label_dec(struct jump_label_key *key); | 128 | extern void static_key_slow_dec(struct static_key *key); |
61 | extern void jump_label_dec_deferred(struct jump_label_key_deferred *key); | 129 | extern void static_key_slow_dec_deferred(struct static_key_deferred *key); |
62 | extern bool jump_label_enabled(struct jump_label_key *key); | ||
63 | extern void jump_label_apply_nops(struct module *mod); | 130 | extern void jump_label_apply_nops(struct module *mod); |
64 | extern void jump_label_rate_limit(struct jump_label_key_deferred *key, | 131 | extern void |
65 | unsigned long rl); | 132 | jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl); |
133 | |||
134 | #define STATIC_KEY_INIT_TRUE ((struct static_key) \ | ||
135 | { .enabled = ATOMIC_INIT(1), .entries = (void *)1 }) | ||
136 | #define STATIC_KEY_INIT_FALSE ((struct static_key) \ | ||
137 | { .enabled = ATOMIC_INIT(0), .entries = (void *)0 }) | ||
66 | 138 | ||
67 | #else /* !HAVE_JUMP_LABEL */ | 139 | #else /* !HAVE_JUMP_LABEL */ |
68 | 140 | ||
69 | #include <linux/atomic.h> | 141 | #include <linux/atomic.h> |
70 | 142 | ||
71 | #define JUMP_LABEL_INIT {ATOMIC_INIT(0)} | 143 | struct static_key { |
72 | |||
73 | struct jump_label_key { | ||
74 | atomic_t enabled; | 144 | atomic_t enabled; |
75 | }; | 145 | }; |
76 | 146 | ||
@@ -78,30 +148,45 @@ static __always_inline void jump_label_init(void) | |||
78 | { | 148 | { |
79 | } | 149 | } |
80 | 150 | ||
81 | struct jump_label_key_deferred { | 151 | struct static_key_deferred { |
82 | struct jump_label_key key; | 152 | struct static_key key; |
83 | }; | 153 | }; |
84 | 154 | ||
85 | static __always_inline bool static_branch(struct jump_label_key *key) | 155 | static __always_inline bool static_key_false(struct static_key *key) |
156 | { | ||
157 | if (unlikely(atomic_read(&key->enabled)) > 0) | ||
158 | return true; | ||
159 | return false; | ||
160 | } | ||
161 | |||
162 | static __always_inline bool static_key_true(struct static_key *key) | ||
86 | { | 163 | { |
87 | if (unlikely(atomic_read(&key->enabled))) | 164 | if (likely(atomic_read(&key->enabled)) > 0) |
88 | return true; | 165 | return true; |
89 | return false; | 166 | return false; |
90 | } | 167 | } |
91 | 168 | ||
92 | static inline void jump_label_inc(struct jump_label_key *key) | 169 | /* Deprecated. Please use 'static_key_false() instead. */ |
170 | static __always_inline bool static_branch(struct static_key *key) | ||
171 | { | ||
172 | if (unlikely(atomic_read(&key->enabled)) > 0) | ||
173 | return true; | ||
174 | return false; | ||
175 | } | ||
176 | |||
177 | static inline void static_key_slow_inc(struct static_key *key) | ||
93 | { | 178 | { |
94 | atomic_inc(&key->enabled); | 179 | atomic_inc(&key->enabled); |
95 | } | 180 | } |
96 | 181 | ||
97 | static inline void jump_label_dec(struct jump_label_key *key) | 182 | static inline void static_key_slow_dec(struct static_key *key) |
98 | { | 183 | { |
99 | atomic_dec(&key->enabled); | 184 | atomic_dec(&key->enabled); |
100 | } | 185 | } |
101 | 186 | ||
102 | static inline void jump_label_dec_deferred(struct jump_label_key_deferred *key) | 187 | static inline void static_key_slow_dec_deferred(struct static_key_deferred *key) |
103 | { | 188 | { |
104 | jump_label_dec(&key->key); | 189 | static_key_slow_dec(&key->key); |
105 | } | 190 | } |
106 | 191 | ||
107 | static inline int jump_label_text_reserved(void *start, void *end) | 192 | static inline int jump_label_text_reserved(void *start, void *end) |
@@ -112,23 +197,30 @@ static inline int jump_label_text_reserved(void *start, void *end) | |||
112 | static inline void jump_label_lock(void) {} | 197 | static inline void jump_label_lock(void) {} |
113 | static inline void jump_label_unlock(void) {} | 198 | static inline void jump_label_unlock(void) {} |
114 | 199 | ||
115 | static inline bool jump_label_enabled(struct jump_label_key *key) | ||
116 | { | ||
117 | return !!atomic_read(&key->enabled); | ||
118 | } | ||
119 | |||
120 | static inline int jump_label_apply_nops(struct module *mod) | 200 | static inline int jump_label_apply_nops(struct module *mod) |
121 | { | 201 | { |
122 | return 0; | 202 | return 0; |
123 | } | 203 | } |
124 | 204 | ||
125 | static inline void jump_label_rate_limit(struct jump_label_key_deferred *key, | 205 | static inline void |
206 | jump_label_rate_limit(struct static_key_deferred *key, | ||
126 | unsigned long rl) | 207 | unsigned long rl) |
127 | { | 208 | { |
128 | } | 209 | } |
210 | |||
211 | #define STATIC_KEY_INIT_TRUE ((struct static_key) \ | ||
212 | { .enabled = ATOMIC_INIT(1) }) | ||
213 | #define STATIC_KEY_INIT_FALSE ((struct static_key) \ | ||
214 | { .enabled = ATOMIC_INIT(0) }) | ||
215 | |||
129 | #endif /* HAVE_JUMP_LABEL */ | 216 | #endif /* HAVE_JUMP_LABEL */ |
130 | 217 | ||
131 | #define jump_label_key_enabled ((struct jump_label_key){ .enabled = ATOMIC_INIT(1), }) | 218 | #define STATIC_KEY_INIT STATIC_KEY_INIT_FALSE |
132 | #define jump_label_key_disabled ((struct jump_label_key){ .enabled = ATOMIC_INIT(0), }) | 219 | #define jump_label_enabled static_key_enabled |
220 | |||
221 | static inline bool static_key_enabled(struct static_key *key) | ||
222 | { | ||
223 | return (atomic_read(&key->enabled) > 0); | ||
224 | } | ||
133 | 225 | ||
134 | #endif /* _LINUX_JUMP_LABEL_H */ | 226 | #endif /* _LINUX_JUMP_LABEL_H */ |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 0eac07c95255..7dfaae7846ab 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -214,8 +214,8 @@ enum { | |||
214 | #include <linux/skbuff.h> | 214 | #include <linux/skbuff.h> |
215 | 215 | ||
216 | #ifdef CONFIG_RPS | 216 | #ifdef CONFIG_RPS |
217 | #include <linux/jump_label.h> | 217 | #include <linux/static_key.h> |
218 | extern struct jump_label_key rps_needed; | 218 | extern struct static_key rps_needed; |
219 | #endif | 219 | #endif |
220 | 220 | ||
221 | struct neighbour; | 221 | struct neighbour; |
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h index b809265607d0..29734be334c1 100644 --- a/include/linux/netfilter.h +++ b/include/linux/netfilter.h | |||
@@ -163,13 +163,13 @@ extern struct ctl_path nf_net_ipv4_netfilter_sysctl_path[]; | |||
163 | extern struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; | 163 | extern struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; |
164 | 164 | ||
165 | #if defined(CONFIG_JUMP_LABEL) | 165 | #if defined(CONFIG_JUMP_LABEL) |
166 | #include <linux/jump_label.h> | 166 | #include <linux/static_key.h> |
167 | extern struct jump_label_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; | 167 | extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; |
168 | static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook) | 168 | static inline bool nf_hooks_active(u_int8_t pf, unsigned int hook) |
169 | { | 169 | { |
170 | if (__builtin_constant_p(pf) && | 170 | if (__builtin_constant_p(pf) && |
171 | __builtin_constant_p(hook)) | 171 | __builtin_constant_p(hook)) |
172 | return static_branch(&nf_hooks_needed[pf][hook]); | 172 | return static_key_false(&nf_hooks_needed[pf][hook]); |
173 | 173 | ||
174 | return !list_empty(&nf_hooks[pf][hook]); | 174 | return !list_empty(&nf_hooks[pf][hook]); |
175 | } | 175 | } |
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index abb2776be1ba..64426b71381f 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
@@ -291,12 +291,14 @@ struct perf_event_mmap_page { | |||
291 | __s64 offset; /* add to hardware event value */ | 291 | __s64 offset; /* add to hardware event value */ |
292 | __u64 time_enabled; /* time event active */ | 292 | __u64 time_enabled; /* time event active */ |
293 | __u64 time_running; /* time event on cpu */ | 293 | __u64 time_running; /* time event on cpu */ |
294 | __u32 time_mult, time_shift; | ||
295 | __u64 time_offset; | ||
294 | 296 | ||
295 | /* | 297 | /* |
296 | * Hole for extension of the self monitor capabilities | 298 | * Hole for extension of the self monitor capabilities |
297 | */ | 299 | */ |
298 | 300 | ||
299 | __u64 __reserved[123]; /* align to 1k */ | 301 | __u64 __reserved[121]; /* align to 1k */ |
300 | 302 | ||
301 | /* | 303 | /* |
302 | * Control data for the mmap() data buffer. | 304 | * Control data for the mmap() data buffer. |
@@ -512,7 +514,7 @@ struct perf_guest_info_callbacks { | |||
512 | #include <linux/ftrace.h> | 514 | #include <linux/ftrace.h> |
513 | #include <linux/cpu.h> | 515 | #include <linux/cpu.h> |
514 | #include <linux/irq_work.h> | 516 | #include <linux/irq_work.h> |
515 | #include <linux/jump_label.h> | 517 | #include <linux/static_key.h> |
516 | #include <linux/atomic.h> | 518 | #include <linux/atomic.h> |
517 | #include <asm/local.h> | 519 | #include <asm/local.h> |
518 | 520 | ||
@@ -616,6 +618,7 @@ struct pmu { | |||
616 | struct list_head entry; | 618 | struct list_head entry; |
617 | 619 | ||
618 | struct device *dev; | 620 | struct device *dev; |
621 | const struct attribute_group **attr_groups; | ||
619 | char *name; | 622 | char *name; |
620 | int type; | 623 | int type; |
621 | 624 | ||
@@ -681,6 +684,12 @@ struct pmu { | |||
681 | * for each successful ->add() during the transaction. | 684 | * for each successful ->add() during the transaction. |
682 | */ | 685 | */ |
683 | void (*cancel_txn) (struct pmu *pmu); /* optional */ | 686 | void (*cancel_txn) (struct pmu *pmu); /* optional */ |
687 | |||
688 | /* | ||
689 | * Will return the value for perf_event_mmap_page::index for this event, | ||
690 | * if no implementation is provided it will default to: event->hw.idx + 1. | ||
691 | */ | ||
692 | int (*event_idx) (struct perf_event *event); /*optional */ | ||
684 | }; | 693 | }; |
685 | 694 | ||
686 | /** | 695 | /** |
@@ -850,6 +859,9 @@ struct perf_event { | |||
850 | #ifdef CONFIG_EVENT_TRACING | 859 | #ifdef CONFIG_EVENT_TRACING |
851 | struct ftrace_event_call *tp_event; | 860 | struct ftrace_event_call *tp_event; |
852 | struct event_filter *filter; | 861 | struct event_filter *filter; |
862 | #ifdef CONFIG_FUNCTION_TRACER | ||
863 | struct ftrace_ops ftrace_ops; | ||
864 | #endif | ||
853 | #endif | 865 | #endif |
854 | 866 | ||
855 | #ifdef CONFIG_CGROUP_PERF | 867 | #ifdef CONFIG_CGROUP_PERF |
@@ -1029,7 +1041,7 @@ static inline int is_software_event(struct perf_event *event) | |||
1029 | return event->pmu->task_ctx_nr == perf_sw_context; | 1041 | return event->pmu->task_ctx_nr == perf_sw_context; |
1030 | } | 1042 | } |
1031 | 1043 | ||
1032 | extern struct jump_label_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; | 1044 | extern struct static_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; |
1033 | 1045 | ||
1034 | extern void __perf_sw_event(u32, u64, struct pt_regs *, u64); | 1046 | extern void __perf_sw_event(u32, u64, struct pt_regs *, u64); |
1035 | 1047 | ||
@@ -1057,7 +1069,7 @@ perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) | |||
1057 | { | 1069 | { |
1058 | struct pt_regs hot_regs; | 1070 | struct pt_regs hot_regs; |
1059 | 1071 | ||
1060 | if (static_branch(&perf_swevent_enabled[event_id])) { | 1072 | if (static_key_false(&perf_swevent_enabled[event_id])) { |
1061 | if (!regs) { | 1073 | if (!regs) { |
1062 | perf_fetch_caller_regs(&hot_regs); | 1074 | perf_fetch_caller_regs(&hot_regs); |
1063 | regs = &hot_regs; | 1075 | regs = &hot_regs; |
@@ -1066,12 +1078,12 @@ perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) | |||
1066 | } | 1078 | } |
1067 | } | 1079 | } |
1068 | 1080 | ||
1069 | extern struct jump_label_key_deferred perf_sched_events; | 1081 | extern struct static_key_deferred perf_sched_events; |
1070 | 1082 | ||
1071 | static inline void perf_event_task_sched_in(struct task_struct *prev, | 1083 | static inline void perf_event_task_sched_in(struct task_struct *prev, |
1072 | struct task_struct *task) | 1084 | struct task_struct *task) |
1073 | { | 1085 | { |
1074 | if (static_branch(&perf_sched_events.key)) | 1086 | if (static_key_false(&perf_sched_events.key)) |
1075 | __perf_event_task_sched_in(prev, task); | 1087 | __perf_event_task_sched_in(prev, task); |
1076 | } | 1088 | } |
1077 | 1089 | ||
@@ -1080,7 +1092,7 @@ static inline void perf_event_task_sched_out(struct task_struct *prev, | |||
1080 | { | 1092 | { |
1081 | perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0); | 1093 | perf_sw_event(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, NULL, 0); |
1082 | 1094 | ||
1083 | if (static_branch(&perf_sched_events.key)) | 1095 | if (static_key_false(&perf_sched_events.key)) |
1084 | __perf_event_task_sched_out(prev, next); | 1096 | __perf_event_task_sched_out(prev, next); |
1085 | } | 1097 | } |
1086 | 1098 | ||
diff --git a/include/linux/static_key.h b/include/linux/static_key.h new file mode 100644 index 000000000000..27bd3f8a0857 --- /dev/null +++ b/include/linux/static_key.h | |||
@@ -0,0 +1 @@ | |||
#include <linux/jump_label.h> | |||
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index df0a779c1bbd..bd96ecd0e05c 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
@@ -17,7 +17,7 @@ | |||
17 | #include <linux/errno.h> | 17 | #include <linux/errno.h> |
18 | #include <linux/types.h> | 18 | #include <linux/types.h> |
19 | #include <linux/rcupdate.h> | 19 | #include <linux/rcupdate.h> |
20 | #include <linux/jump_label.h> | 20 | #include <linux/static_key.h> |
21 | 21 | ||
22 | struct module; | 22 | struct module; |
23 | struct tracepoint; | 23 | struct tracepoint; |
@@ -29,7 +29,7 @@ struct tracepoint_func { | |||
29 | 29 | ||
30 | struct tracepoint { | 30 | struct tracepoint { |
31 | const char *name; /* Tracepoint name */ | 31 | const char *name; /* Tracepoint name */ |
32 | struct jump_label_key key; | 32 | struct static_key key; |
33 | void (*regfunc)(void); | 33 | void (*regfunc)(void); |
34 | void (*unregfunc)(void); | 34 | void (*unregfunc)(void); |
35 | struct tracepoint_func __rcu *funcs; | 35 | struct tracepoint_func __rcu *funcs; |
@@ -114,7 +114,7 @@ static inline void tracepoint_synchronize_unregister(void) | |||
114 | * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just | 114 | * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just |
115 | * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto". | 115 | * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto". |
116 | */ | 116 | */ |
117 | #define __DO_TRACE(tp, proto, args, cond) \ | 117 | #define __DO_TRACE(tp, proto, args, cond, prercu, postrcu) \ |
118 | do { \ | 118 | do { \ |
119 | struct tracepoint_func *it_func_ptr; \ | 119 | struct tracepoint_func *it_func_ptr; \ |
120 | void *it_func; \ | 120 | void *it_func; \ |
@@ -122,6 +122,7 @@ static inline void tracepoint_synchronize_unregister(void) | |||
122 | \ | 122 | \ |
123 | if (!(cond)) \ | 123 | if (!(cond)) \ |
124 | return; \ | 124 | return; \ |
125 | prercu; \ | ||
125 | rcu_read_lock_sched_notrace(); \ | 126 | rcu_read_lock_sched_notrace(); \ |
126 | it_func_ptr = rcu_dereference_sched((tp)->funcs); \ | 127 | it_func_ptr = rcu_dereference_sched((tp)->funcs); \ |
127 | if (it_func_ptr) { \ | 128 | if (it_func_ptr) { \ |
@@ -132,6 +133,7 @@ static inline void tracepoint_synchronize_unregister(void) | |||
132 | } while ((++it_func_ptr)->func); \ | 133 | } while ((++it_func_ptr)->func); \ |
133 | } \ | 134 | } \ |
134 | rcu_read_unlock_sched_notrace(); \ | 135 | rcu_read_unlock_sched_notrace(); \ |
136 | postrcu; \ | ||
135 | } while (0) | 137 | } while (0) |
136 | 138 | ||
137 | /* | 139 | /* |
@@ -139,15 +141,25 @@ static inline void tracepoint_synchronize_unregister(void) | |||
139 | * not add unwanted padding between the beginning of the section and the | 141 | * not add unwanted padding between the beginning of the section and the |
140 | * structure. Force alignment to the same alignment as the section start. | 142 | * structure. Force alignment to the same alignment as the section start. |
141 | */ | 143 | */ |
142 | #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \ | 144 | #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \ |
143 | extern struct tracepoint __tracepoint_##name; \ | 145 | extern struct tracepoint __tracepoint_##name; \ |
144 | static inline void trace_##name(proto) \ | 146 | static inline void trace_##name(proto) \ |
145 | { \ | 147 | { \ |
148 | if (static_key_false(&__tracepoint_##name.key)) \ | ||
149 | __DO_TRACE(&__tracepoint_##name, \ | ||
150 | TP_PROTO(data_proto), \ | ||
151 | TP_ARGS(data_args), \ | ||
152 | TP_CONDITION(cond),,); \ | ||
153 | } \ | ||
154 | static inline void trace_##name##_rcuidle(proto) \ | ||
155 | { \ | ||
146 | if (static_branch(&__tracepoint_##name.key)) \ | 156 | if (static_branch(&__tracepoint_##name.key)) \ |
147 | __DO_TRACE(&__tracepoint_##name, \ | 157 | __DO_TRACE(&__tracepoint_##name, \ |
148 | TP_PROTO(data_proto), \ | 158 | TP_PROTO(data_proto), \ |
149 | TP_ARGS(data_args), \ | 159 | TP_ARGS(data_args), \ |
150 | TP_CONDITION(cond)); \ | 160 | TP_CONDITION(cond), \ |
161 | rcu_idle_exit(), \ | ||
162 | rcu_idle_enter()); \ | ||
151 | } \ | 163 | } \ |
152 | static inline int \ | 164 | static inline int \ |
153 | register_trace_##name(void (*probe)(data_proto), void *data) \ | 165 | register_trace_##name(void (*probe)(data_proto), void *data) \ |
@@ -176,7 +188,7 @@ static inline void tracepoint_synchronize_unregister(void) | |||
176 | __attribute__((section("__tracepoints_strings"))) = #name; \ | 188 | __attribute__((section("__tracepoints_strings"))) = #name; \ |
177 | struct tracepoint __tracepoint_##name \ | 189 | struct tracepoint __tracepoint_##name \ |
178 | __attribute__((section("__tracepoints"))) = \ | 190 | __attribute__((section("__tracepoints"))) = \ |
179 | { __tpstrtab_##name, JUMP_LABEL_INIT, reg, unreg, NULL };\ | 191 | { __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\ |
180 | static struct tracepoint * const __tracepoint_ptr_##name __used \ | 192 | static struct tracepoint * const __tracepoint_ptr_##name __used \ |
181 | __attribute__((section("__tracepoints_ptrs"))) = \ | 193 | __attribute__((section("__tracepoints_ptrs"))) = \ |
182 | &__tracepoint_##name; | 194 | &__tracepoint_##name; |
@@ -190,9 +202,11 @@ static inline void tracepoint_synchronize_unregister(void) | |||
190 | EXPORT_SYMBOL(__tracepoint_##name) | 202 | EXPORT_SYMBOL(__tracepoint_##name) |
191 | 203 | ||
192 | #else /* !CONFIG_TRACEPOINTS */ | 204 | #else /* !CONFIG_TRACEPOINTS */ |
193 | #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \ | 205 | #define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \ |
194 | static inline void trace_##name(proto) \ | 206 | static inline void trace_##name(proto) \ |
195 | { } \ | 207 | { } \ |
208 | static inline void trace_##name##_rcuidle(proto) \ | ||
209 | { } \ | ||
196 | static inline int \ | 210 | static inline int \ |
197 | register_trace_##name(void (*probe)(data_proto), \ | 211 | register_trace_##name(void (*probe)(data_proto), \ |
198 | void *data) \ | 212 | void *data) \ |