The wakeup tracer has three types of function tracers. Normal function tracer, function graph entry, and function graph return. Each of these use a complex dance to prevent recursion and whether to trace the data or not (depending on the wake_task variable). This patch moves the duplicate code into a single routine, to prevent future mistakes with modifying duplicate complex code.
Showing the changes to kernel (1 of 1 file). Show all
Unified · Split
| @@ -56,43 +56,73 @@ static struct tracer_flags tracer_flags = { · 55 unmodified lines | ||
| 56 | 56 | #define is_graph() (tracer_flags.val & TRACE_DISPLAY_GRAPH) |
| 57 | 57 | |
| 58 | 58 | #ifdef CONFIG_FUNCTION_TRACER |
| 59 | + | |
| 59 | 60 | /* |
| 60 | − * wakeup uses its own tracer function to keep the overhead down: | |
| 61 | + * Prologue for the wakeup function tracers. | |
| 62 | + * | |
| 63 | + * Returns 1 if it is OK to continue, and preemption | |
| 64 | + * is disabled and data->disabled is incremented. | |
| 65 | + * 0 if the trace is to be ignored, and preemption | |
| 66 | + * is not disabled and data->disabled is | |
| 67 | + * kept the same. | |
| 68 | + * | |
| 69 | + * Note, this function is also used outside this ifdef but | |
| 70 | + * inside the #ifdef of the function graph tracer below. | |
| 71 | + * This is OK, since the function graph tracer is | |
| 72 | + * dependent on the function tracer. | |
| 61 | 73 | */ |
| 62 | −static void | |
| 63 | −wakeup_tracer_call(unsigned long ip, unsigned long parent_ip) | |
| 74 | +static int | |
| 75 | +func_prolog_preempt_disable(struct trace_array *tr, | |
| 76 | + struct trace_array_cpu **data, | |
| 77 | + int *pc) | |
| 64 | 78 | { |
| 65 | − struct trace_array *tr = wakeup_trace; | |
| 66 | − struct trace_array_cpu *data; | |
| 67 | − unsigned long flags; | |
| 68 | 79 | long disabled; |
| 69 | 80 | int cpu; |
| 70 | − int pc; | |
| 71 | 81 | |
| 72 | 82 | if (likely(!wakeup_task)) |
| 73 | − return; | |
| 83 | + return 0; | |
| 74 | 84 | |
| 75 | − pc = preempt_count(); | |
| 85 | + *pc = preempt_count(); | |
| 76 | 86 | preempt_disable_notrace(); |
| 77 | 87 | |
| 78 | 88 | cpu = raw_smp_processor_id(); |
| 79 | 89 | if (cpu != wakeup_current_cpu) |
| 80 | 90 | goto out_enable; |
| 81 | 91 | |
| 82 | − data = tr->data[cpu]; | |
| 83 | − disabled = atomic_inc_return(&data->disabled); | |
| 92 | + *data = tr->data[cpu]; | |
| 93 | + disabled = atomic_inc_return(&(*data)->disabled); | |
| 84 | 94 | if (unlikely(disabled != 1)) |
| 85 | 95 | goto out; |
| 86 | 96 | |
| 87 | − local_irq_save(flags); | |
| 97 | + return 1; | |
| 88 | 98 | |
| 89 | − trace_function(tr, ip, parent_ip, flags, pc); | |
| 99 | +out: | |
| 100 | + atomic_dec(&(*data)->disabled); | |
| 101 | + | |
| 102 | +out_enable: | |
| 103 | + preempt_enable_notrace(); | |
| 104 | + return 0; | |
| 105 | +} | |
| 106 | + | |
| 107 | +/* | |
| 108 | + * wakeup uses its own tracer function to keep the overhead down: | |
| 109 | + */ | |
| 110 | +static void | |
| 111 | +wakeup_tracer_call(unsigned long ip, unsigned long parent_ip) | |
| 112 | +{ | |
| 113 | + struct trace_array *tr = wakeup_trace; | |
| 114 | + struct trace_array_cpu *data; | |
| 115 | + unsigned long flags; | |
| 116 | + int pc; | |
| 117 | + | |
| 118 | + if (!func_prolog_preempt_disable(tr, &data, &pc)) | |
| 119 | + return; | |
| 90 | 120 | |
| 121 | + local_irq_save(flags); | |
| 122 | + trace_function(tr, ip, parent_ip, flags, pc); | |
| 91 | 123 | local_irq_restore(flags); |
| 92 | 124 | |
| 93 | − out: | |
| 94 | 125 | atomic_dec(&data->disabled); |
| 95 | − out_enable: | |
| 96 | 126 | preempt_enable_notrace(); |
| 97 | 127 | } |
| 98 | 128 | |
| @@ -154,32 +184,16 @@ static int wakeup_graph_entry(struct ftrace_graph_ent *trace) · 55 unmodified lines | ||
| 154 | 184 | struct trace_array *tr = wakeup_trace; |
| 155 | 185 | struct trace_array_cpu *data; |
| 156 | 186 | unsigned long flags; |
| 157 | − long disabled; | |
| 158 | − int cpu, pc, ret = 0; | |
| 187 | + int pc, ret = 0; | |
| 159 | 188 | |
| 160 | − if (likely(!wakeup_task)) | |
| 189 | + if (!func_prolog_preempt_disable(tr, &data, &pc)) | |
| 161 | 190 | return 0; |
| 162 | 191 | |
| 163 | − pc = preempt_count(); | |
| 164 | − preempt_disable_notrace(); | |
| 165 | − | |
| 166 | − cpu = raw_smp_processor_id(); | |
| 167 | − if (cpu != wakeup_current_cpu) | |
| 168 | − goto out_enable; | |
| 169 | − | |
| 170 | − data = tr->data[cpu]; | |
| 171 | − disabled = atomic_inc_return(&data->disabled); | |
| 172 | − if (unlikely(disabled != 1)) | |
| 173 | − goto out; | |
| 174 | − | |
| 175 | 192 | local_save_flags(flags); |
| 176 | 193 | ret = __trace_graph_entry(tr, trace, flags, pc); |
| 177 | − | |
| 178 | −out: | |
| 179 | 194 | atomic_dec(&data->disabled); |
| 180 | − | |
| 181 | −out_enable: | |
| 182 | 195 | preempt_enable_notrace(); |
| 196 | + | |
| 183 | 197 | return ret; |
| 184 | 198 | } |
| 185 | 199 | |
| @@ -188,31 +202,15 @@ static void wakeup_graph_return(struct ftrace_graph_ret *trace) · 2 unmodified lines | ||
| 188 | 202 | struct trace_array *tr = wakeup_trace; |
| 189 | 203 | struct trace_array_cpu *data; |
| 190 | 204 | unsigned long flags; |
| 191 | − long disabled; | |
| 192 | − int cpu, pc; | |
| 205 | + int pc; | |
| 193 | 206 | |
| 194 | − if (likely(!wakeup_task)) | |
| 207 | + if (!func_prolog_preempt_disable(tr, &data, &pc)) | |
| 195 | 208 | return; |
| 196 | 209 | |
| 197 | − pc = preempt_count(); | |
| 198 | − preempt_disable_notrace(); | |
| 199 | − | |
| 200 | − cpu = raw_smp_processor_id(); | |
| 201 | − if (cpu != wakeup_current_cpu) | |
| 202 | − goto out_enable; | |
| 203 | − | |
| 204 | − data = tr->data[cpu]; | |
| 205 | − disabled = atomic_inc_return(&data->disabled); | |
| 206 | − if (unlikely(disabled != 1)) | |
| 207 | − goto out; | |
| 208 | − | |
| 209 | 210 | local_save_flags(flags); |
| 210 | 211 | __trace_graph_return(tr, trace, flags, pc); |
| 211 | − | |
| 212 | −out: | |
| 213 | 212 | atomic_dec(&data->disabled); |
| 214 | 213 | |
| 215 | −out_enable: | |
| 216 | 214 | preempt_enable_notrace(); |
| 217 | 215 | return; |
| 218 | 216 | } |