Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'tip/perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace into perf/core

+667 -117
+70 -3
include/linux/ftrace.h
··· 31 31 32 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 49 enum { 35 50 FTRACE_OPS_FL_ENABLED = 1 << 0, 36 51 FTRACE_OPS_FL_GLOBAL = 1 << 1, 37 52 FTRACE_OPS_FL_DYNAMIC = 1 << 2, 53 + FTRACE_OPS_FL_CONTROL = 1 << 3, 38 54 }; 39 55 40 56 struct ftrace_ops { 41 57 ftrace_func_t func; 42 58 struct ftrace_ops *next; 43 59 unsigned long flags; 60 + int __percpu *disabled; 44 61 #ifdef CONFIG_DYNAMIC_FTRACE 45 62 struct ftrace_hash *notrace_hash; 46 63 struct ftrace_hash *filter_hash; ··· 113 96 int register_ftrace_function(struct ftrace_ops *ops); 114 97 int unregister_ftrace_function(struct ftrace_ops *ops); 115 98 void clear_ftrace_function(void); 99 + 100 + /** 101 + * ftrace_function_local_enable - enable controlled ftrace_ops on current cpu 102 + * 103 + * This function enables tracing on current cpu by decreasing 104 + * the per cpu control variable. 105 + * It must be called with preemption disabled and only on ftrace_ops 106 + * registered with FTRACE_OPS_FL_CONTROL. If called without preemption 107 + * disabled, this_cpu_ptr will complain when CONFIG_DEBUG_PREEMPT is enabled. 108 + */ 109 + static inline void ftrace_function_local_enable(struct ftrace_ops *ops) 110 + { 111 + if (WARN_ON_ONCE(!(ops->flags & FTRACE_OPS_FL_CONTROL))) 112 + return; 113 + 114 + (*this_cpu_ptr(ops->disabled))--; 115 + } 116 + 117 + /** 118 + * ftrace_function_local_disable - 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_disable(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_disabled - returns ftrace_ops disabled value 136 + * on current cpu 137 + * 138 + * This function returns value of ftrace_ops::disabled on current cpu. 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 int ftrace_function_local_disabled(struct ftrace_ops *ops) 144 + { 145 + WARN_ON_ONCE(!(ops->flags & FTRACE_OPS_FL_CONTROL)); 146 + return *this_cpu_ptr(ops->disabled); 147 + } 116 148 117 149 extern void ftrace_stub(unsigned long a0, unsigned long a1); 118 150 ··· 250 184 int len, int reset); 251 185 void ftrace_set_global_filter(unsigned char *buf, int len, int reset); 252 186 void ftrace_set_global_notrace(unsigned char *buf, int len, int reset); 187 + void ftrace_free_filter(struct ftrace_ops *ops); 253 188 254 189 int register_ftrace_command(struct ftrace_func_command *cmd); 255 190 int unregister_ftrace_command(struct ftrace_func_command *cmd); ··· 381 314 #else 382 315 static inline int skip_trace(unsigned long ip) { return 0; } 383 316 static inline int ftrace_force_update(void) { return 0; } 384 - static inline void ftrace_set_filter(unsigned char *buf, int len, int reset) 385 - { 386 - } 387 317 static inline void ftrace_disable_daemon(void) { } 388 318 static inline void ftrace_enable_daemon(void) { } 389 319 static inline void ftrace_release_mod(struct module *mod) {} ··· 404 340 */ 405 341 #define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; }) 406 342 #define ftrace_set_early_filter(ops, buf, enable) do { } while (0) 343 + #define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; }) 344 + #define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; }) 345 + #define ftrace_free_filter(ops) do { } while (0) 407 346 408 347 static inline ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf, 409 348 size_t cnt, loff_t *ppos) { return -ENODEV; }
+7 -2
include/linux/ftrace_event.h
··· 146 146 TRACE_REG_UNREGISTER, 147 147 TRACE_REG_PERF_REGISTER, 148 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 155 struct ftrace_event_call; ··· 161 157 void *perf_probe; 162 158 #endif 163 159 int (*reg)(struct ftrace_event_call *event, 164 - enum trace_reg type); 160 + enum trace_reg type, void *data); 165 161 int (*define_fields)(struct ftrace_event_call *); 166 162 struct list_head *(*get_fields)(struct ftrace_event_call *); 167 163 struct list_head fields; ··· 169 165 }; 170 166 171 167 extern int ftrace_event_reg(struct ftrace_event_call *event, 172 - enum trace_reg type); 168 + enum trace_reg type, void *data); 173 169 174 170 enum { 175 171 TRACE_EVENT_FL_ENABLED_BIT, ··· 245 241 FILTER_STATIC_STRING, 246 242 FILTER_DYN_STRING, 247 243 FILTER_PTR_STRING, 244 + FILTER_TRACE_FN, 248 245 }; 249 246 250 247 #define EVENT_STORAGE_SIZE 128
+3
include/linux/perf_event.h
··· 859 859 #ifdef CONFIG_EVENT_TRACING 860 860 struct ftrace_event_call *tp_event; 861 861 struct event_filter *filter; 862 + #ifdef CONFIG_FUNCTION_TRACER 863 + struct ftrace_ops ftrace_ops; 864 + #endif 862 865 #endif 863 866 864 867 #ifdef CONFIG_CGROUP_PERF
+110 -7
kernel/trace/ftrace.c
··· 62 62 #define FTRACE_HASH_DEFAULT_BITS 10 63 63 #define FTRACE_HASH_MAX_BITS 12 64 64 65 + #define FL_GLOBAL_CONTROL_MASK (FTRACE_OPS_FL_GLOBAL | FTRACE_OPS_FL_CONTROL) 66 + 65 67 /* ftrace_enabled is a method to turn ftrace on or off */ 66 68 int ftrace_enabled __read_mostly; 67 69 static int last_ftrace_enabled; ··· 91 89 }; 92 90 93 91 static struct ftrace_ops *ftrace_global_list __read_mostly = &ftrace_list_end; 92 + static struct ftrace_ops *ftrace_control_list __read_mostly = &ftrace_list_end; 94 93 static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end; 95 94 ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; 96 95 static ftrace_func_t __ftrace_trace_function_delay __read_mostly = ftrace_stub; 97 96 ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub; 98 97 ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub; 99 98 static struct ftrace_ops global_ops; 99 + static struct ftrace_ops control_ops; 100 100 101 101 static void 102 102 ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip); ··· 171 167 __ftrace_trace_function(ip, parent_ip); 172 168 } 173 169 #endif 170 + 171 + static void control_ops_disable_all(struct ftrace_ops *ops) 172 + { 173 + int cpu; 174 + 175 + for_each_possible_cpu(cpu) 176 + *per_cpu_ptr(ops->disabled, cpu) = 1; 177 + } 178 + 179 + static int control_ops_alloc(struct ftrace_ops *ops) 180 + { 181 + int __percpu *disabled; 182 + 183 + disabled = alloc_percpu(int); 184 + if (!disabled) 185 + return -ENOMEM; 186 + 187 + ops->disabled = disabled; 188 + control_ops_disable_all(ops); 189 + return 0; 190 + } 191 + 192 + static void control_ops_free(struct ftrace_ops *ops) 193 + { 194 + free_percpu(ops->disabled); 195 + } 174 196 175 197 static void update_global_ops(void) 176 198 { ··· 289 259 return 0; 290 260 } 291 261 262 + static void add_ftrace_list_ops(struct ftrace_ops **list, 263 + struct ftrace_ops *main_ops, 264 + struct ftrace_ops *ops) 265 + { 266 + int first = *list == &ftrace_list_end; 267 + add_ftrace_ops(list, ops); 268 + if (first) 269 + add_ftrace_ops(&ftrace_ops_list, main_ops); 270 + } 271 + 272 + static int remove_ftrace_list_ops(struct ftrace_ops **list, 273 + struct ftrace_ops *main_ops, 274 + struct ftrace_ops *ops) 275 + { 276 + int ret = remove_ftrace_ops(list, ops); 277 + if (!ret && *list == &ftrace_list_end) 278 + ret = remove_ftrace_ops(&ftrace_ops_list, main_ops); 279 + return ret; 280 + } 281 + 292 282 static int __register_ftrace_function(struct ftrace_ops *ops) 293 283 { 294 284 if (ftrace_disabled) ··· 320 270 if (WARN_ON(ops->flags & FTRACE_OPS_FL_ENABLED)) 321 271 return -EBUSY; 322 272 273 + /* We don't support both control and global flags set. */ 274 + if ((ops->flags & FL_GLOBAL_CONTROL_MASK) == FL_GLOBAL_CONTROL_MASK) 275 + return -EINVAL; 276 + 323 277 if (!core_kernel_data((unsigned long)ops)) 324 278 ops->flags |= FTRACE_OPS_FL_DYNAMIC; 325 279 326 280 if (ops->flags & FTRACE_OPS_FL_GLOBAL) { 327 - int first = ftrace_global_list == &ftrace_list_end; 328 - add_ftrace_ops(&ftrace_global_list, ops); 281 + add_ftrace_list_ops(&ftrace_global_list, &global_ops, ops); 329 282 ops->flags |= FTRACE_OPS_FL_ENABLED; 330 - if (first) 331 - add_ftrace_ops(&ftrace_ops_list, &global_ops); 283 + } else if (ops->flags & FTRACE_OPS_FL_CONTROL) { 284 + if (control_ops_alloc(ops)) 285 + return -ENOMEM; 286 + add_ftrace_list_ops(&ftrace_control_list, &control_ops, ops); 332 287 } else 333 288 add_ftrace_ops(&ftrace_ops_list, ops); 334 289 ··· 357 302 return -EINVAL; 358 303 359 304 if (ops->flags & FTRACE_OPS_FL_GLOBAL) { 360 - ret = remove_ftrace_ops(&ftrace_global_list, ops); 361 - if (!ret && ftrace_global_list == &ftrace_list_end) 362 - ret = remove_ftrace_ops(&ftrace_ops_list, &global_ops); 305 + ret = remove_ftrace_list_ops(&ftrace_global_list, 306 + &global_ops, ops); 363 307 if (!ret) 364 308 ops->flags &= ~FTRACE_OPS_FL_ENABLED; 309 + } else if (ops->flags & FTRACE_OPS_FL_CONTROL) { 310 + ret = remove_ftrace_list_ops(&ftrace_control_list, 311 + &control_ops, ops); 312 + if (!ret) { 313 + /* 314 + * The ftrace_ops is now removed from the list, 315 + * so there'll be no new users. We must ensure 316 + * all current users are done before we free 317 + * the control data. 318 + */ 319 + synchronize_sched(); 320 + control_ops_free(ops); 321 + } 365 322 } else 366 323 ret = remove_ftrace_ops(&ftrace_ops_list, ops); 367 324 ··· 1184 1117 if (!hash || hash == EMPTY_HASH) 1185 1118 return; 1186 1119 call_rcu_sched(&hash->rcu, __free_ftrace_hash_rcu); 1120 + } 1121 + 1122 + void ftrace_free_filter(struct ftrace_ops *ops) 1123 + { 1124 + free_ftrace_hash(ops->filter_hash); 1125 + free_ftrace_hash(ops->notrace_hash); 1187 1126 } 1188 1127 1189 1128 static struct ftrace_hash *alloc_ftrace_hash(int size_bits) ··· 3945 3872 } 3946 3873 3947 3874 #endif /* CONFIG_DYNAMIC_FTRACE */ 3875 + 3876 + static void 3877 + ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip) 3878 + { 3879 + struct ftrace_ops *op; 3880 + 3881 + if (unlikely(trace_recursion_test(TRACE_CONTROL_BIT))) 3882 + return; 3883 + 3884 + /* 3885 + * Some of the ops may be dynamically allocated, 3886 + * they must be freed after a synchronize_sched(). 3887 + */ 3888 + preempt_disable_notrace(); 3889 + trace_recursion_set(TRACE_CONTROL_BIT); 3890 + op = rcu_dereference_raw(ftrace_control_list); 3891 + while (op != &ftrace_list_end) { 3892 + if (!ftrace_function_local_disabled(op) && 3893 + ftrace_ops_test(op, ip)) 3894 + op->func(ip, parent_ip); 3895 + 3896 + op = rcu_dereference_raw(op->next); 3897 + }; 3898 + trace_recursion_clear(TRACE_CONTROL_BIT); 3899 + preempt_enable_notrace(); 3900 + } 3901 + 3902 + static struct ftrace_ops control_ops = { 3903 + .func = ftrace_ops_control_func, 3904 + }; 3948 3905 3949 3906 static void 3950 3907 ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip)
+28 -10
kernel/trace/trace.h
··· 56 56 #define F_STRUCT(args...) args 57 57 58 58 #undef FTRACE_ENTRY 59 - #define FTRACE_ENTRY(name, struct_name, id, tstruct, print) \ 60 - struct struct_name { \ 61 - struct trace_entry ent; \ 62 - tstruct \ 59 + #define FTRACE_ENTRY(name, struct_name, id, tstruct, print, filter) \ 60 + struct struct_name { \ 61 + struct trace_entry ent; \ 62 + tstruct \ 63 63 } 64 64 65 65 #undef TP_ARGS 66 66 #define TP_ARGS(args...) args 67 67 68 68 #undef FTRACE_ENTRY_DUP 69 - #define FTRACE_ENTRY_DUP(name, name_struct, id, tstruct, printk) 69 + #define FTRACE_ENTRY_DUP(name, name_struct, id, tstruct, printk, filter) 70 + 71 + #undef FTRACE_ENTRY_REG 72 + #define FTRACE_ENTRY_REG(name, struct_name, id, tstruct, print, \ 73 + filter, regfn) \ 74 + FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \ 75 + filter) 70 76 71 77 #include "trace_entries.h" 72 78 ··· 294 288 /* for function tracing recursion */ 295 289 #define TRACE_INTERNAL_BIT (1<<11) 296 290 #define TRACE_GLOBAL_BIT (1<<12) 291 + #define TRACE_CONTROL_BIT (1<<13) 292 + 297 293 /* 298 294 * Abuse of the trace_recursion. 299 295 * As we need a way to maintain state if we are tracing the function ··· 597 589 static inline int ftrace_is_dead(void) { return 0; } 598 590 #endif 599 591 592 + int ftrace_event_is_function(struct ftrace_event_call *call); 593 + 600 594 /* 601 595 * struct trace_parser - servers for reading the user input separated by spaces 602 596 * @cont: set if the input is not complete - no final space char was found ··· 776 766 u64 val; 777 767 struct regex regex; 778 768 unsigned short *ops; 779 - #ifdef CONFIG_FTRACE_STARTUP_TEST 780 769 struct ftrace_event_field *field; 781 - #endif 782 770 int offset; 783 771 int not; 784 772 int op; ··· 826 818 extern const char *__stop___trace_bprintk_fmt[]; 827 819 828 820 #undef FTRACE_ENTRY 829 - #define FTRACE_ENTRY(call, struct_name, id, tstruct, print) \ 821 + #define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter) \ 830 822 extern struct ftrace_event_call \ 831 823 __attribute__((__aligned__(4))) event_##call; 832 824 #undef FTRACE_ENTRY_DUP 833 - #define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print) \ 834 - FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print)) 825 + #define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print, filter) \ 826 + FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print), \ 827 + filter) 835 828 #include "trace_entries.h" 829 + 830 + #ifdef CONFIG_PERF_EVENTS 831 + #ifdef CONFIG_FUNCTION_TRACER 832 + int perf_ftrace_event_register(struct ftrace_event_call *call, 833 + enum trace_reg type, void *data); 834 + #else 835 + #define perf_ftrace_event_register NULL 836 + #endif /* CONFIG_FUNCTION_TRACER */ 837 + #endif /* CONFIG_PERF_EVENTS */ 836 838 837 839 #endif /* _LINUX_KERNEL_TRACE_H */
+39 -15
kernel/trace/trace_entries.h
··· 55 55 /* 56 56 * Function trace entry - function address and parent function address: 57 57 */ 58 - FTRACE_ENTRY(function, ftrace_entry, 58 + FTRACE_ENTRY_REG(function, ftrace_entry, 59 59 60 60 TRACE_FN, 61 61 ··· 64 64 __field( unsigned long, parent_ip ) 65 65 ), 66 66 67 - F_printk(" %lx <-- %lx", __entry->ip, __entry->parent_ip) 67 + F_printk(" %lx <-- %lx", __entry->ip, __entry->parent_ip), 68 + 69 + FILTER_TRACE_FN, 70 + 71 + perf_ftrace_event_register 68 72 ); 69 73 70 74 /* Function call entry */ ··· 82 78 __field_desc( int, graph_ent, depth ) 83 79 ), 84 80 85 - F_printk("--> %lx (%d)", __entry->func, __entry->depth) 81 + F_printk("--> %lx (%d)", __entry->func, __entry->depth), 82 + 83 + FILTER_OTHER 86 84 ); 87 85 88 86 /* Function return entry */ ··· 104 98 F_printk("<-- %lx (%d) (start: %llx end: %llx) over: %d", 105 99 __entry->func, __entry->depth, 106 100 __entry->calltime, __entry->rettime, 107 - __entry->depth) 101 + __entry->depth), 102 + 103 + FILTER_OTHER 108 104 ); 109 105 110 106 /* ··· 135 127 F_printk("%u:%u:%u ==> %u:%u:%u [%03u]", 136 128 __entry->prev_pid, __entry->prev_prio, __entry->prev_state, 137 129 __entry->next_pid, __entry->next_prio, __entry->next_state, 138 - __entry->next_cpu 139 - ) 130 + __entry->next_cpu), 131 + 132 + FILTER_OTHER 140 133 ); 141 134 142 135 /* ··· 155 146 F_printk("%u:%u:%u ==+ %u:%u:%u [%03u]", 156 147 __entry->prev_pid, __entry->prev_prio, __entry->prev_state, 157 148 __entry->next_pid, __entry->next_prio, __entry->next_state, 158 - __entry->next_cpu 159 - ) 149 + __entry->next_cpu), 150 + 151 + FILTER_OTHER 160 152 ); 161 153 162 154 /* ··· 179 169 "\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n", 180 170 __entry->caller[0], __entry->caller[1], __entry->caller[2], 181 171 __entry->caller[3], __entry->caller[4], __entry->caller[5], 182 - __entry->caller[6], __entry->caller[7]) 172 + __entry->caller[6], __entry->caller[7]), 173 + 174 + FILTER_OTHER 183 175 ); 184 176 185 177 FTRACE_ENTRY(user_stack, userstack_entry, ··· 197 185 "\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n\t=> (%08lx)\n", 198 186 __entry->caller[0], __entry->caller[1], __entry->caller[2], 199 187 __entry->caller[3], __entry->caller[4], __entry->caller[5], 200 - __entry->caller[6], __entry->caller[7]) 188 + __entry->caller[6], __entry->caller[7]), 189 + 190 + FILTER_OTHER 201 191 ); 202 192 203 193 /* ··· 216 202 ), 217 203 218 204 F_printk("%08lx fmt:%p", 219 - __entry->ip, __entry->fmt) 205 + __entry->ip, __entry->fmt), 206 + 207 + FILTER_OTHER 220 208 ); 221 209 222 210 FTRACE_ENTRY(print, print_entry, ··· 231 215 ), 232 216 233 217 F_printk("%08lx %s", 234 - __entry->ip, __entry->buf) 218 + __entry->ip, __entry->buf), 219 + 220 + FILTER_OTHER 235 221 ); 236 222 237 223 FTRACE_ENTRY(mmiotrace_rw, trace_mmiotrace_rw, ··· 252 234 253 235 F_printk("%lx %lx %lx %d %x %x", 254 236 (unsigned long)__entry->phys, __entry->value, __entry->pc, 255 - __entry->map_id, __entry->opcode, __entry->width) 237 + __entry->map_id, __entry->opcode, __entry->width), 238 + 239 + FILTER_OTHER 256 240 ); 257 241 258 242 FTRACE_ENTRY(mmiotrace_map, trace_mmiotrace_map, ··· 272 252 273 253 F_printk("%lx %lx %lx %d %x", 274 254 (unsigned long)__entry->phys, __entry->virt, __entry->len, 275 - __entry->map_id, __entry->opcode) 255 + __entry->map_id, __entry->opcode), 256 + 257 + FILTER_OTHER 276 258 ); 277 259 278 260 ··· 294 272 295 273 F_printk("%u:%s:%s (%u)", 296 274 __entry->line, 297 - __entry->func, __entry->file, __entry->correct) 275 + __entry->func, __entry->file, __entry->correct), 276 + 277 + FILTER_OTHER 298 278 ); 299 279
+166 -42
kernel/trace/trace_event_perf.c
··· 24 24 static int perf_trace_event_perm(struct ftrace_event_call *tp_event, 25 25 struct perf_event *p_event) 26 26 { 27 + /* The ftrace function trace is allowed only for root. */ 28 + if (ftrace_event_is_function(tp_event) && 29 + perf_paranoid_kernel() && !capable(CAP_SYS_ADMIN)) 30 + return -EPERM; 31 + 27 32 /* No tracing, just counting, so no obvious leak */ 28 33 if (!(p_event->attr.sample_type & PERF_SAMPLE_RAW)) 29 34 return 0; ··· 49 44 return 0; 50 45 } 51 46 52 - static int perf_trace_event_init(struct ftrace_event_call *tp_event, 53 - struct perf_event *p_event) 47 + static int perf_trace_event_reg(struct ftrace_event_call *tp_event, 48 + struct perf_event *p_event) 54 49 { 55 50 struct hlist_head __percpu *list; 56 - int ret; 51 + int ret = -ENOMEM; 57 52 int cpu; 58 - 59 - ret = perf_trace_event_perm(tp_event, p_event); 60 - if (ret) 61 - return ret; 62 53 63 54 p_event->tp_event = tp_event; 64 55 if (tp_event->perf_refcount++ > 0) 65 56 return 0; 66 - 67 - ret = -ENOMEM; 68 57 69 58 list = alloc_percpu(struct hlist_head); 70 59 if (!list) ··· 82 83 } 83 84 } 84 85 85 - ret = tp_event->class->reg(tp_event, TRACE_REG_PERF_REGISTER); 86 + ret = tp_event->class->reg(tp_event, TRACE_REG_PERF_REGISTER, NULL); 86 87 if (ret) 87 88 goto fail; 88 89 ··· 107 108 return ret; 108 109 } 109 110 111 + static void perf_trace_event_unreg(struct perf_event *p_event) 112 + { 113 + struct ftrace_event_call *tp_event = p_event->tp_event; 114 + int i; 115 + 116 + if (--tp_event->perf_refcount > 0) 117 + goto out; 118 + 119 + tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER, NULL); 120 + 121 + /* 122 + * Ensure our callback won't be called anymore. The buffers 123 + * will be freed after that. 124 + */ 125 + tracepoint_synchronize_unregister(); 126 + 127 + free_percpu(tp_event->perf_events); 128 + tp_event->perf_events = NULL; 129 + 130 + if (!--total_ref_count) { 131 + for (i = 0; i < PERF_NR_CONTEXTS; i++) { 132 + free_percpu(perf_trace_buf[i]); 133 + perf_trace_buf[i] = NULL; 134 + } 135 + } 136 + out: 137 + module_put(tp_event->mod); 138 + } 139 + 140 + static int perf_trace_event_open(struct perf_event *p_event) 141 + { 142 + struct ftrace_event_call *tp_event = p_event->tp_event; 143 + return tp_event->class->reg(tp_event, TRACE_REG_PERF_OPEN, p_event); 144 + } 145 + 146 + static void perf_trace_event_close(struct perf_event *p_event) 147 + { 148 + struct ftrace_event_call *tp_event = p_event->tp_event; 149 + tp_event->class->reg(tp_event, TRACE_REG_PERF_CLOSE, p_event); 150 + } 151 + 152 + static int perf_trace_event_init(struct ftrace_event_call *tp_event, 153 + struct perf_event *p_event) 154 + { 155 + int ret; 156 + 157 + ret = perf_trace_event_perm(tp_event, p_event); 158 + if (ret) 159 + return ret; 160 + 161 + ret = perf_trace_event_reg(tp_event, p_event); 162 + if (ret) 163 + return ret; 164 + 165 + ret = perf_trace_event_open(p_event); 166 + if (ret) { 167 + perf_trace_event_unreg(p_event); 168 + return ret; 169 + } 170 + 171 + return 0; 172 + } 173 + 110 174 int perf_trace_init(struct perf_event *p_event) 111 175 { 112 176 struct ftrace_event_call *tp_event; ··· 192 130 return ret; 193 131 } 194 132 133 + void perf_trace_destroy(struct perf_event *p_event) 134 + { 135 + mutex_lock(&event_mutex); 136 + perf_trace_event_close(p_event); 137 + perf_trace_event_unreg(p_event); 138 + mutex_unlock(&event_mutex); 139 + } 140 + 195 141 int perf_trace_add(struct perf_event *p_event, int flags) 196 142 { 197 143 struct ftrace_event_call *tp_event = p_event->tp_event; ··· 216 146 list = this_cpu_ptr(pcpu_list); 217 147 hlist_add_head_rcu(&p_event->hlist_entry, list); 218 148 219 - return 0; 149 + return tp_event->class->reg(tp_event, TRACE_REG_PERF_ADD, p_event); 220 150 } 221 151 222 152 void perf_trace_del(struct perf_event *p_event, int flags) 223 153 { 224 - hlist_del_rcu(&p_event->hlist_entry); 225 - } 226 - 227 - void perf_trace_destroy(struct perf_event *p_event) 228 - { 229 154 struct ftrace_event_call *tp_event = p_event->tp_event; 230 - int i; 231 - 232 - mutex_lock(&event_mutex); 233 - if (--tp_event->perf_refcount > 0) 234 - goto out; 235 - 236 - tp_event->class->reg(tp_event, TRACE_REG_PERF_UNREGISTER); 237 - 238 - /* 239 - * Ensure our callback won't be called anymore. The buffers 240 - * will be freed after that. 241 - */ 242 - tracepoint_synchronize_unregister(); 243 - 244 - free_percpu(tp_event->perf_events); 245 - tp_event->perf_events = NULL; 246 - 247 - if (!--total_ref_count) { 248 - for (i = 0; i < PERF_NR_CONTEXTS; i++) { 249 - free_percpu(perf_trace_buf[i]); 250 - perf_trace_buf[i] = NULL; 251 - } 252 - } 253 - out: 254 - module_put(tp_event->mod); 255 - mutex_unlock(&event_mutex); 155 + hlist_del_rcu(&p_event->hlist_entry); 156 + tp_event->class->reg(tp_event, TRACE_REG_PERF_DEL, p_event); 256 157 } 257 158 258 159 __kprobes void *perf_trace_buf_prepare(int size, unsigned short type, ··· 255 214 return raw_data; 256 215 } 257 216 EXPORT_SYMBOL_GPL(perf_trace_buf_prepare); 217 + 218 + #ifdef CONFIG_FUNCTION_TRACER 219 + static void 220 + perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip) 221 + { 222 + struct ftrace_entry *entry; 223 + struct hlist_head *head; 224 + struct pt_regs regs; 225 + int rctx; 226 + 227 + #define ENTRY_SIZE (ALIGN(sizeof(struct ftrace_entry) + sizeof(u32), \ 228 + sizeof(u64)) - sizeof(u32)) 229 + 230 + BUILD_BUG_ON(ENTRY_SIZE > PERF_MAX_TRACE_SIZE); 231 + 232 + perf_fetch_caller_regs(&regs); 233 + 234 + entry = perf_trace_buf_prepare(ENTRY_SIZE, TRACE_FN, NULL, &rctx); 235 + if (!entry) 236 + return; 237 + 238 + entry->ip = ip; 239 + entry->parent_ip = parent_ip; 240 + 241 + head = this_cpu_ptr(event_function.perf_events); 242 + perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, 0, 243 + 1, &regs, head); 244 + 245 + #undef ENTRY_SIZE 246 + } 247 + 248 + static int perf_ftrace_function_register(struct perf_event *event) 249 + { 250 + struct ftrace_ops *ops = &event->ftrace_ops; 251 + 252 + ops->flags |= FTRACE_OPS_FL_CONTROL; 253 + ops->func = perf_ftrace_function_call; 254 + return register_ftrace_function(ops); 255 + } 256 + 257 + static int perf_ftrace_function_unregister(struct perf_event *event) 258 + { 259 + struct ftrace_ops *ops = &event->ftrace_ops; 260 + int ret = unregister_ftrace_function(ops); 261 + ftrace_free_filter(ops); 262 + return ret; 263 + } 264 + 265 + static void perf_ftrace_function_enable(struct perf_event *event) 266 + { 267 + ftrace_function_local_enable(&event->ftrace_ops); 268 + } 269 + 270 + static void perf_ftrace_function_disable(struct perf_event *event) 271 + { 272 + ftrace_function_local_disable(&event->ftrace_ops); 273 + } 274 + 275 + int perf_ftrace_event_register(struct ftrace_event_call *call, 276 + enum trace_reg type, void *data) 277 + { 278 + switch (type) { 279 + case TRACE_REG_REGISTER: 280 + case TRACE_REG_UNREGISTER: 281 + break; 282 + case TRACE_REG_PERF_REGISTER: 283 + case TRACE_REG_PERF_UNREGISTER: 284 + return 0; 285 + case TRACE_REG_PERF_OPEN: 286 + return perf_ftrace_function_register(data); 287 + case TRACE_REG_PERF_CLOSE: 288 + return perf_ftrace_function_unregister(data); 289 + case TRACE_REG_PERF_ADD: 290 + perf_ftrace_function_enable(data); 291 + return 0; 292 + case TRACE_REG_PERF_DEL: 293 + perf_ftrace_function_disable(data); 294 + return 0; 295 + } 296 + 297 + return -EINVAL; 298 + } 299 + #endif /* CONFIG_FUNCTION_TRACER */
+9 -3
kernel/trace/trace_events.c
··· 147 147 } 148 148 EXPORT_SYMBOL_GPL(trace_event_raw_init); 149 149 150 - int ftrace_event_reg(struct ftrace_event_call *call, enum trace_reg type) 150 + int ftrace_event_reg(struct ftrace_event_call *call, 151 + enum trace_reg type, void *data) 151 152 { 152 153 switch (type) { 153 154 case TRACE_REG_REGISTER: ··· 170 169 tracepoint_probe_unregister(call->name, 171 170 call->class->perf_probe, 172 171 call); 172 + return 0; 173 + case TRACE_REG_PERF_OPEN: 174 + case TRACE_REG_PERF_CLOSE: 175 + case TRACE_REG_PERF_ADD: 176 + case TRACE_REG_PERF_DEL: 173 177 return 0; 174 178 #endif 175 179 } ··· 215 209 tracing_stop_cmdline_record(); 216 210 call->flags &= ~TRACE_EVENT_FL_RECORDED_CMD; 217 211 } 218 - call->class->reg(call, TRACE_REG_UNREGISTER); 212 + call->class->reg(call, TRACE_REG_UNREGISTER, NULL); 219 213 } 220 214 break; 221 215 case 1: ··· 224 218 tracing_start_cmdline_record(); 225 219 call->flags |= TRACE_EVENT_FL_RECORDED_CMD; 226 220 } 227 - ret = call->class->reg(call, TRACE_REG_REGISTER); 221 + ret = call->class->reg(call, TRACE_REG_REGISTER, NULL); 228 222 if (ret) { 229 223 tracing_stop_cmdline_record(); 230 224 pr_info("event trace: Could not enable event "
+163 -5
kernel/trace/trace_events_filter.c
··· 81 81 FILT_ERR_TOO_MANY_PREDS, 82 82 FILT_ERR_MISSING_FIELD, 83 83 FILT_ERR_INVALID_FILTER, 84 + FILT_ERR_IP_FIELD_ONLY, 84 85 }; 85 86 86 87 static char *err_text[] = { ··· 97 96 "Too many terms in predicate expression", 98 97 "Missing field name and/or value", 99 98 "Meaningless filter expression", 99 + "Only 'ip' field is supported for function trace", 100 100 }; 101 101 102 102 struct opstack_op { ··· 901 899 return FILTER_OTHER; 902 900 } 903 901 902 + static bool is_function_field(struct ftrace_event_field *field) 903 + { 904 + return field->filter_type == FILTER_TRACE_FN; 905 + } 906 + 904 907 static bool is_string_field(struct ftrace_event_field *field) 905 908 { 906 909 return field->filter_type == FILTER_DYN_STRING || ··· 993 986 fn = filter_pred_strloc; 994 987 else 995 988 fn = filter_pred_pchar; 989 + } else if (is_function_field(field)) { 990 + if (strcmp(field->name, "ip")) { 991 + parse_error(ps, FILT_ERR_IP_FIELD_ONLY, 0); 992 + return -EINVAL; 993 + } 996 994 } else { 997 995 if (field->is_signed) 998 996 ret = strict_strtoll(pred->regex.pattern, 0, &val); ··· 1345 1333 1346 1334 strcpy(pred.regex.pattern, operand2); 1347 1335 pred.regex.len = strlen(pred.regex.pattern); 1348 - 1349 - #ifdef CONFIG_FTRACE_STARTUP_TEST 1350 1336 pred.field = field; 1351 - #endif 1352 1337 return init_pred(ps, field, &pred) ? NULL : &pred; 1353 1338 } 1354 1339 ··· 1958 1949 __free_filter(filter); 1959 1950 } 1960 1951 1952 + struct function_filter_data { 1953 + struct ftrace_ops *ops; 1954 + int first_filter; 1955 + int first_notrace; 1956 + }; 1957 + 1958 + #ifdef CONFIG_FUNCTION_TRACER 1959 + static char ** 1960 + ftrace_function_filter_re(char *buf, int len, int *count) 1961 + { 1962 + char *str, *sep, **re; 1963 + 1964 + str = kstrndup(buf, len, GFP_KERNEL); 1965 + if (!str) 1966 + return NULL; 1967 + 1968 + /* 1969 + * The argv_split function takes white space 1970 + * as a separator, so convert ',' into spaces. 1971 + */ 1972 + while ((sep = strchr(str, ','))) 1973 + *sep = ' '; 1974 + 1975 + re = argv_split(GFP_KERNEL, str, count); 1976 + kfree(str); 1977 + return re; 1978 + } 1979 + 1980 + static int ftrace_function_set_regexp(struct ftrace_ops *ops, int filter, 1981 + int reset, char *re, int len) 1982 + { 1983 + int ret; 1984 + 1985 + if (filter) 1986 + ret = ftrace_set_filter(ops, re, len, reset); 1987 + else 1988 + ret = ftrace_set_notrace(ops, re, len, reset); 1989 + 1990 + return ret; 1991 + } 1992 + 1993 + static int __ftrace_function_set_filter(int filter, char *buf, int len, 1994 + struct function_filter_data *data) 1995 + { 1996 + int i, re_cnt, ret; 1997 + int *reset; 1998 + char **re; 1999 + 2000 + reset = filter ? &data->first_filter : &data->first_notrace; 2001 + 2002 + /* 2003 + * The 'ip' field could have multiple filters set, separated 2004 + * either by space or comma. We first cut the filter and apply 2005 + * all pieces separatelly. 2006 + */ 2007 + re = ftrace_function_filter_re(buf, len, &re_cnt); 2008 + if (!re) 2009 + return -EINVAL; 2010 + 2011 + for (i = 0; i < re_cnt; i++) { 2012 + ret = ftrace_function_set_regexp(data->ops, filter, *reset, 2013 + re[i], strlen(re[i])); 2014 + if (ret) 2015 + break; 2016 + 2017 + if (*reset) 2018 + *reset = 0; 2019 + } 2020 + 2021 + argv_free(re); 2022 + return ret; 2023 + } 2024 + 2025 + static int ftrace_function_check_pred(struct filter_pred *pred, int leaf) 2026 + { 2027 + struct ftrace_event_field *field = pred->field; 2028 + 2029 + if (leaf) { 2030 + /* 2031 + * Check the leaf predicate for function trace, verify: 2032 + * - only '==' and '!=' is used 2033 + * - the 'ip' field is used 2034 + */ 2035 + if ((pred->op != OP_EQ) && (pred->op != OP_NE)) 2036 + return -EINVAL; 2037 + 2038 + if (strcmp(field->name, "ip")) 2039 + return -EINVAL; 2040 + } else { 2041 + /* 2042 + * Check the non leaf predicate for function trace, verify: 2043 + * - only '||' is used 2044 + */ 2045 + if (pred->op != OP_OR) 2046 + return -EINVAL; 2047 + } 2048 + 2049 + return 0; 2050 + } 2051 + 2052 + static int ftrace_function_set_filter_cb(enum move_type move, 2053 + struct filter_pred *pred, 2054 + int *err, void *data) 2055 + { 2056 + /* Checking the node is valid for function trace. */ 2057 + if ((move != MOVE_DOWN) || 2058 + (pred->left != FILTER_PRED_INVALID)) { 2059 + *err = ftrace_function_check_pred(pred, 0); 2060 + } else { 2061 + *err = ftrace_function_check_pred(pred, 1); 2062 + if (*err) 2063 + return WALK_PRED_ABORT; 2064 + 2065 + *err = __ftrace_function_set_filter(pred->op == OP_EQ, 2066 + pred->regex.pattern, 2067 + pred->regex.len, 2068 + data); 2069 + } 2070 + 2071 + return (*err) ? WALK_PRED_ABORT : WALK_PRED_DEFAULT; 2072 + } 2073 + 2074 + static int ftrace_function_set_filter(struct perf_event *event, 2075 + struct event_filter *filter) 2076 + { 2077 + struct function_filter_data data = { 2078 + .first_filter = 1, 2079 + .first_notrace = 1, 2080 + .ops = &event->ftrace_ops, 2081 + }; 2082 + 2083 + return walk_pred_tree(filter->preds, filter->root, 2084 + ftrace_function_set_filter_cb, &data); 2085 + } 2086 + #else 2087 + static int ftrace_function_set_filter(struct perf_event *event, 2088 + struct event_filter *filter) 2089 + { 2090 + return -ENODEV; 2091 + } 2092 + #endif /* CONFIG_FUNCTION_TRACER */ 2093 + 1961 2094 int ftrace_profile_set_filter(struct perf_event *event, int event_id, 1962 2095 char *filter_str) 1963 2096 { ··· 2120 1969 goto out_unlock; 2121 1970 2122 1971 err = create_filter(call, filter_str, false, &filter); 2123 - if (!err) 2124 - event->filter = filter; 1972 + if (err) 1973 + goto free_filter; 1974 + 1975 + if (ftrace_event_is_function(call)) 1976 + err = ftrace_function_set_filter(event, filter); 2125 1977 else 1978 + event->filter = filter; 1979 + 1980 + free_filter: 1981 + if (err || ftrace_event_is_function(call)) 2126 1982 __free_filter(filter); 2127 1983 2128 1984 out_unlock:
+44 -20
kernel/trace/trace_export.c
··· 18 18 #undef TRACE_SYSTEM 19 19 #define TRACE_SYSTEM ftrace 20 20 21 + /* 22 + * The FTRACE_ENTRY_REG macro allows ftrace entry to define register 23 + * function and thus become accesible via perf. 24 + */ 25 + #undef FTRACE_ENTRY_REG 26 + #define FTRACE_ENTRY_REG(name, struct_name, id, tstruct, print, \ 27 + filter, regfn) \ 28 + FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \ 29 + filter) 30 + 21 31 /* not needed for this file */ 22 32 #undef __field_struct 23 33 #define __field_struct(type, item) ··· 54 44 #define F_printk(fmt, args...) fmt, args 55 45 56 46 #undef FTRACE_ENTRY 57 - #define FTRACE_ENTRY(name, struct_name, id, tstruct, print) \ 58 - struct ____ftrace_##name { \ 59 - tstruct \ 60 - }; \ 61 - static void __always_unused ____ftrace_check_##name(void) \ 62 - { \ 63 - struct ____ftrace_##name *__entry = NULL; \ 64 - \ 65 - /* force compile-time check on F_printk() */ \ 66 - printk(print); \ 47 + #define FTRACE_ENTRY(name, struct_name, id, tstruct, print, filter) \ 48 + struct ____ftrace_##name { \ 49 + tstruct \ 50 + }; \ 51 + static void __always_unused ____ftrace_check_##name(void) \ 52 + { \ 53 + struct ____ftrace_##name *__entry = NULL; \ 54 + \ 55 + /* force compile-time check on F_printk() */ \ 56 + printk(print); \ 67 57 } 68 58 69 59 #undef FTRACE_ENTRY_DUP 70 - #define FTRACE_ENTRY_DUP(name, struct_name, id, tstruct, print) \ 71 - FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print)) 60 + #define FTRACE_ENTRY_DUP(name, struct_name, id, tstruct, print, filter) \ 61 + FTRACE_ENTRY(name, struct_name, id, PARAMS(tstruct), PARAMS(print), \ 62 + filter) 72 63 73 64 #include "trace_entries.h" 74 65 ··· 78 67 ret = trace_define_field(event_call, #type, #item, \ 79 68 offsetof(typeof(field), item), \ 80 69 sizeof(field.item), \ 81 - is_signed_type(type), FILTER_OTHER); \ 70 + is_signed_type(type), filter_type); \ 82 71 if (ret) \ 83 72 return ret; 84 73 ··· 88 77 offsetof(typeof(field), \ 89 78 container.item), \ 90 79 sizeof(field.container.item), \ 91 - is_signed_type(type), FILTER_OTHER); \ 80 + is_signed_type(type), filter_type); \ 92 81 if (ret) \ 93 82 return ret; 94 83 ··· 102 91 ret = trace_define_field(event_call, event_storage, #item, \ 103 92 offsetof(typeof(field), item), \ 104 93 sizeof(field.item), \ 105 - is_signed_type(type), FILTER_OTHER); \ 94 + is_signed_type(type), filter_type); \ 106 95 mutex_unlock(&event_storage_mutex); \ 107 96 if (ret) \ 108 97 return ret; \ ··· 115 104 offsetof(typeof(field), \ 116 105 container.item), \ 117 106 sizeof(field.container.item), \ 118 - is_signed_type(type), FILTER_OTHER); \ 107 + is_signed_type(type), filter_type); \ 119 108 if (ret) \ 120 109 return ret; 121 110 ··· 123 112 #define __dynamic_array(type, item) \ 124 113 ret = trace_define_field(event_call, #type, #item, \ 125 114 offsetof(typeof(field), item), \ 126 - 0, is_signed_type(type), FILTER_OTHER);\ 115 + 0, is_signed_type(type), filter_type);\ 127 116 if (ret) \ 128 117 return ret; 129 118 130 119 #undef FTRACE_ENTRY 131 - #define FTRACE_ENTRY(name, struct_name, id, tstruct, print) \ 120 + #define FTRACE_ENTRY(name, struct_name, id, tstruct, print, filter) \ 132 121 int \ 133 122 ftrace_define_fields_##name(struct ftrace_event_call *event_call) \ 134 123 { \ 135 124 struct struct_name field; \ 136 125 int ret; \ 126 + int filter_type = filter; \ 137 127 \ 138 128 tstruct; \ 139 129 \ ··· 164 152 #undef F_printk 165 153 #define F_printk(fmt, args...) #fmt ", " __stringify(args) 166 154 167 - #undef FTRACE_ENTRY 168 - #define FTRACE_ENTRY(call, struct_name, etype, tstruct, print) \ 155 + #undef FTRACE_ENTRY_REG 156 + #define FTRACE_ENTRY_REG(call, struct_name, etype, tstruct, print, filter,\ 157 + regfn) \ 169 158 \ 170 159 struct ftrace_event_class event_class_ftrace_##call = { \ 171 160 .system = __stringify(TRACE_SYSTEM), \ 172 161 .define_fields = ftrace_define_fields_##call, \ 173 162 .fields = LIST_HEAD_INIT(event_class_ftrace_##call.fields),\ 163 + .reg = regfn, \ 174 164 }; \ 175 165 \ 176 166 struct ftrace_event_call __used event_##call = { \ ··· 183 169 }; \ 184 170 struct ftrace_event_call __used \ 185 171 __attribute__((section("_ftrace_events"))) *__event_##call = &event_##call; 172 + 173 + #undef FTRACE_ENTRY 174 + #define FTRACE_ENTRY(call, struct_name, etype, tstruct, print, filter) \ 175 + FTRACE_ENTRY_REG(call, struct_name, etype, \ 176 + PARAMS(tstruct), PARAMS(print), filter, NULL) 177 + 178 + int ftrace_event_is_function(struct ftrace_event_call *call) 179 + { 180 + return call == &event_function; 181 + } 186 182 187 183 #include "trace_entries.h"
+7 -1
kernel/trace/trace_kprobe.c
··· 1892 1892 #endif /* CONFIG_PERF_EVENTS */ 1893 1893 1894 1894 static __kprobes 1895 - int kprobe_register(struct ftrace_event_call *event, enum trace_reg type) 1895 + int kprobe_register(struct ftrace_event_call *event, 1896 + enum trace_reg type, void *data) 1896 1897 { 1897 1898 struct trace_probe *tp = (struct trace_probe *)event->data; 1898 1899 ··· 1909 1908 return enable_trace_probe(tp, TP_FLAG_PROFILE); 1910 1909 case TRACE_REG_PERF_UNREGISTER: 1911 1910 disable_trace_probe(tp, TP_FLAG_PROFILE); 1911 + return 0; 1912 + case TRACE_REG_PERF_OPEN: 1913 + case TRACE_REG_PERF_CLOSE: 1914 + case TRACE_REG_PERF_ADD: 1915 + case TRACE_REG_PERF_DEL: 1912 1916 return 0; 1913 1917 #endif 1914 1918 }
+7 -5
kernel/trace/trace_output.c
··· 300 300 unsigned long mask; 301 301 const char *str; 302 302 const char *ret = p->buffer + p->len; 303 - int i; 303 + int i, first = 1; 304 304 305 305 for (i = 0; flag_array[i].name && flags; i++) { 306 306 ··· 310 310 311 311 str = flag_array[i].name; 312 312 flags &= ~mask; 313 - if (p->len && delim) 313 + if (!first && delim) 314 314 trace_seq_puts(p, delim); 315 + else 316 + first = 0; 315 317 trace_seq_puts(p, str); 316 318 } 317 319 318 320 /* check for left over flags */ 319 321 if (flags) { 320 - if (p->len && delim) 322 + if (!first && delim) 321 323 trace_seq_puts(p, delim); 322 324 trace_seq_printf(p, "0x%lx", flags); 323 325 } ··· 346 344 break; 347 345 } 348 346 349 - if (!p->len) 347 + if (ret == (const char *)(p->buffer + p->len)) 350 348 trace_seq_printf(p, "0x%lx", val); 351 349 352 350 trace_seq_putc(p, 0); ··· 372 370 break; 373 371 } 374 372 375 - if (!p->len) 373 + if (ret == (const char *)(p->buffer + p->len)) 376 374 trace_seq_printf(p, "0x%llx", val); 377 375 378 376 trace_seq_putc(p, 0);
+14 -4
kernel/trace/trace_syscalls.c
··· 17 17 static DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); 18 18 19 19 static int syscall_enter_register(struct ftrace_event_call *event, 20 - enum trace_reg type); 20 + enum trace_reg type, void *data); 21 21 static int syscall_exit_register(struct ftrace_event_call *event, 22 - enum trace_reg type); 22 + enum trace_reg type, void *data); 23 23 24 24 static int syscall_enter_define_fields(struct ftrace_event_call *call); 25 25 static int syscall_exit_define_fields(struct ftrace_event_call *call); ··· 649 649 #endif /* CONFIG_PERF_EVENTS */ 650 650 651 651 static int syscall_enter_register(struct ftrace_event_call *event, 652 - enum trace_reg type) 652 + enum trace_reg type, void *data) 653 653 { 654 654 switch (type) { 655 655 case TRACE_REG_REGISTER: ··· 664 664 case TRACE_REG_PERF_UNREGISTER: 665 665 perf_sysenter_disable(event); 666 666 return 0; 667 + case TRACE_REG_PERF_OPEN: 668 + case TRACE_REG_PERF_CLOSE: 669 + case TRACE_REG_PERF_ADD: 670 + case TRACE_REG_PERF_DEL: 671 + return 0; 667 672 #endif 668 673 } 669 674 return 0; 670 675 } 671 676 672 677 static int syscall_exit_register(struct ftrace_event_call *event, 673 - enum trace_reg type) 678 + enum trace_reg type, void *data) 674 679 { 675 680 switch (type) { 676 681 case TRACE_REG_REGISTER: ··· 689 684 return perf_sysexit_enable(event); 690 685 case TRACE_REG_PERF_UNREGISTER: 691 686 perf_sysexit_disable(event); 687 + return 0; 688 + case TRACE_REG_PERF_OPEN: 689 + case TRACE_REG_PERF_CLOSE: 690 + case TRACE_REG_PERF_ADD: 691 + case TRACE_REG_PERF_DEL: 692 692 return 0; 693 693 #endif 694 694 }