| .. | .. | 
|---|
| 16 | 16 | #include "trace.h" | 
|---|
| 17 | 17 | #include "trace_output.h" | 
|---|
| 18 | 18 |  | 
|---|
| 19 |  | -static bool kill_ftrace_graph; | 
|---|
| 20 |  | - | 
|---|
| 21 |  | -/** | 
|---|
| 22 |  | - * ftrace_graph_is_dead - returns true if ftrace_graph_stop() was called | 
|---|
| 23 |  | - * | 
|---|
| 24 |  | - * ftrace_graph_stop() is called when a severe error is detected in | 
|---|
| 25 |  | - * the function graph tracing. This function is called by the critical | 
|---|
| 26 |  | - * paths of function graph to keep those paths from doing any more harm. | 
|---|
| 27 |  | - */ | 
|---|
| 28 |  | -bool ftrace_graph_is_dead(void) | 
|---|
| 29 |  | -{ | 
|---|
| 30 |  | -	return kill_ftrace_graph; | 
|---|
| 31 |  | -} | 
|---|
| 32 |  | - | 
|---|
| 33 |  | -/** | 
|---|
| 34 |  | - * ftrace_graph_stop - set to permanently disable function graph tracincg | 
|---|
| 35 |  | - * | 
|---|
| 36 |  | - * In case of an error int function graph tracing, this is called | 
|---|
| 37 |  | - * to try to keep function graph tracing from causing any more harm. | 
|---|
| 38 |  | - * Usually this is pretty severe and this is called to try to at least | 
|---|
| 39 |  | - * get a warning out to the user. | 
|---|
| 40 |  | - */ | 
|---|
| 41 |  | -void ftrace_graph_stop(void) | 
|---|
| 42 |  | -{ | 
|---|
| 43 |  | -	kill_ftrace_graph = true; | 
|---|
| 44 |  | -} | 
|---|
| 45 |  | - | 
|---|
| 46 | 19 | /* When set, irq functions will be ignored */ | 
|---|
| 47 | 20 | static int ftrace_graph_skip_irqs; | 
|---|
| 48 | 21 |  | 
|---|
| .. | .. | 
|---|
| 87 | 60 | { TRACER_OPT(funcgraph-tail, TRACE_GRAPH_PRINT_TAIL) }, | 
|---|
| 88 | 61 | /* Include sleep time (scheduled out) between entry and return */ | 
|---|
| 89 | 62 | { TRACER_OPT(sleep-time, TRACE_GRAPH_SLEEP_TIME) }, | 
|---|
|  | 63 | + | 
|---|
|  | 64 | +#ifdef CONFIG_FUNCTION_PROFILER | 
|---|
| 90 | 65 | /* Include time within nested functions */ | 
|---|
| 91 | 66 | { TRACER_OPT(graph-time, TRACE_GRAPH_GRAPH_TIME) }, | 
|---|
|  | 67 | +#endif | 
|---|
|  | 68 | + | 
|---|
| 92 | 69 | { } /* Empty entry */ | 
|---|
| 93 | 70 | }; | 
|---|
| 94 | 71 |  | 
|---|
| .. | .. | 
|---|
| 117 | 94 | print_graph_duration(struct trace_array *tr, unsigned long long duration, | 
|---|
| 118 | 95 | struct trace_seq *s, u32 flags); | 
|---|
| 119 | 96 |  | 
|---|
| 120 |  | -/* Add a function return address to the trace stack on thread info.*/ | 
|---|
| 121 |  | -static int | 
|---|
| 122 |  | -ftrace_push_return_trace(unsigned long ret, unsigned long func, | 
|---|
| 123 |  | -			 unsigned long frame_pointer, unsigned long *retp) | 
|---|
| 124 |  | -{ | 
|---|
| 125 |  | -	unsigned long long calltime; | 
|---|
| 126 |  | -	int index; | 
|---|
| 127 |  | - | 
|---|
| 128 |  | -	if (unlikely(ftrace_graph_is_dead())) | 
|---|
| 129 |  | -		return -EBUSY; | 
|---|
| 130 |  | - | 
|---|
| 131 |  | -	if (!current->ret_stack) | 
|---|
| 132 |  | -		return -EBUSY; | 
|---|
| 133 |  | - | 
|---|
| 134 |  | -	/* | 
|---|
| 135 |  | -	 * We must make sure the ret_stack is tested before we read | 
|---|
| 136 |  | -	 * anything else. | 
|---|
| 137 |  | -	 */ | 
|---|
| 138 |  | -	smp_rmb(); | 
|---|
| 139 |  | - | 
|---|
| 140 |  | -	/* The return trace stack is full */ | 
|---|
| 141 |  | -	if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) { | 
|---|
| 142 |  | -		atomic_inc(¤t->trace_overrun); | 
|---|
| 143 |  | -		return -EBUSY; | 
|---|
| 144 |  | -	} | 
|---|
| 145 |  | - | 
|---|
| 146 |  | -	/* | 
|---|
| 147 |  | -	 * The curr_ret_stack is an index to ftrace return stack of | 
|---|
| 148 |  | -	 * current task.  Its value should be in [0, FTRACE_RETFUNC_ | 
|---|
| 149 |  | -	 * DEPTH) when the function graph tracer is used.  To support | 
|---|
| 150 |  | -	 * filtering out specific functions, it makes the index | 
|---|
| 151 |  | -	 * negative by subtracting huge value (FTRACE_NOTRACE_DEPTH) | 
|---|
| 152 |  | -	 * so when it sees a negative index the ftrace will ignore | 
|---|
| 153 |  | -	 * the record.  And the index gets recovered when returning | 
|---|
| 154 |  | -	 * from the filtered function by adding the FTRACE_NOTRACE_ | 
|---|
| 155 |  | -	 * DEPTH and then it'll continue to record functions normally. | 
|---|
| 156 |  | -	 * | 
|---|
| 157 |  | -	 * The curr_ret_stack is initialized to -1 and get increased | 
|---|
| 158 |  | -	 * in this function.  So it can be less than -1 only if it was | 
|---|
| 159 |  | -	 * filtered out via ftrace_graph_notrace_addr() which can be | 
|---|
| 160 |  | -	 * set from set_graph_notrace file in tracefs by user. | 
|---|
| 161 |  | -	 */ | 
|---|
| 162 |  | -	if (current->curr_ret_stack < -1) | 
|---|
| 163 |  | -		return -EBUSY; | 
|---|
| 164 |  | - | 
|---|
| 165 |  | -	calltime = trace_clock_local(); | 
|---|
| 166 |  | - | 
|---|
| 167 |  | -	index = ++current->curr_ret_stack; | 
|---|
| 168 |  | -	if (ftrace_graph_notrace_addr(func)) | 
|---|
| 169 |  | -		current->curr_ret_stack -= FTRACE_NOTRACE_DEPTH; | 
|---|
| 170 |  | -	barrier(); | 
|---|
| 171 |  | -	current->ret_stack[index].ret = ret; | 
|---|
| 172 |  | -	current->ret_stack[index].func = func; | 
|---|
| 173 |  | -	current->ret_stack[index].calltime = calltime; | 
|---|
| 174 |  | -#ifdef HAVE_FUNCTION_GRAPH_FP_TEST | 
|---|
| 175 |  | -	current->ret_stack[index].fp = frame_pointer; | 
|---|
| 176 |  | -#endif | 
|---|
| 177 |  | -#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR | 
|---|
| 178 |  | -	current->ret_stack[index].retp = retp; | 
|---|
| 179 |  | -#endif | 
|---|
| 180 |  | -	return 0; | 
|---|
| 181 |  | -} | 
|---|
| 182 |  | - | 
|---|
| 183 |  | -int function_graph_enter(unsigned long ret, unsigned long func, | 
|---|
| 184 |  | -			 unsigned long frame_pointer, unsigned long *retp) | 
|---|
| 185 |  | -{ | 
|---|
| 186 |  | -	struct ftrace_graph_ent trace; | 
|---|
| 187 |  | - | 
|---|
| 188 |  | -	trace.func = func; | 
|---|
| 189 |  | -	trace.depth = ++current->curr_ret_depth; | 
|---|
| 190 |  | - | 
|---|
| 191 |  | -	if (ftrace_push_return_trace(ret, func, | 
|---|
| 192 |  | -				     frame_pointer, retp)) | 
|---|
| 193 |  | -		goto out; | 
|---|
| 194 |  | - | 
|---|
| 195 |  | -	/* Only trace if the calling function expects to */ | 
|---|
| 196 |  | -	if (!ftrace_graph_entry(&trace)) | 
|---|
| 197 |  | -		goto out_ret; | 
|---|
| 198 |  | - | 
|---|
| 199 |  | -	return 0; | 
|---|
| 200 |  | - out_ret: | 
|---|
| 201 |  | -	current->curr_ret_stack--; | 
|---|
| 202 |  | - out: | 
|---|
| 203 |  | -	current->curr_ret_depth--; | 
|---|
| 204 |  | -	return -EBUSY; | 
|---|
| 205 |  | -} | 
|---|
| 206 |  | - | 
|---|
| 207 |  | -/* Retrieve a function return address to the trace stack on thread info.*/ | 
|---|
| 208 |  | -static void | 
|---|
| 209 |  | -ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret, | 
|---|
| 210 |  | -			unsigned long frame_pointer) | 
|---|
| 211 |  | -{ | 
|---|
| 212 |  | -	int index; | 
|---|
| 213 |  | - | 
|---|
| 214 |  | -	index = current->curr_ret_stack; | 
|---|
| 215 |  | - | 
|---|
| 216 |  | -	/* | 
|---|
| 217 |  | -	 * A negative index here means that it's just returned from a | 
|---|
| 218 |  | -	 * notrace'd function.  Recover index to get an original | 
|---|
| 219 |  | -	 * return address.  See ftrace_push_return_trace(). | 
|---|
| 220 |  | -	 * | 
|---|
| 221 |  | -	 * TODO: Need to check whether the stack gets corrupted. | 
|---|
| 222 |  | -	 */ | 
|---|
| 223 |  | -	if (index < 0) | 
|---|
| 224 |  | -		index += FTRACE_NOTRACE_DEPTH; | 
|---|
| 225 |  | - | 
|---|
| 226 |  | -	if (unlikely(index < 0 || index >= FTRACE_RETFUNC_DEPTH)) { | 
|---|
| 227 |  | -		ftrace_graph_stop(); | 
|---|
| 228 |  | -		WARN_ON(1); | 
|---|
| 229 |  | -		/* Might as well panic, otherwise we have no where to go */ | 
|---|
| 230 |  | -		*ret = (unsigned long)panic; | 
|---|
| 231 |  | -		return; | 
|---|
| 232 |  | -	} | 
|---|
| 233 |  | - | 
|---|
| 234 |  | -#ifdef HAVE_FUNCTION_GRAPH_FP_TEST | 
|---|
| 235 |  | -	/* | 
|---|
| 236 |  | -	 * The arch may choose to record the frame pointer used | 
|---|
| 237 |  | -	 * and check it here to make sure that it is what we expect it | 
|---|
| 238 |  | -	 * to be. If gcc does not set the place holder of the return | 
|---|
| 239 |  | -	 * address in the frame pointer, and does a copy instead, then | 
|---|
| 240 |  | -	 * the function graph trace will fail. This test detects this | 
|---|
| 241 |  | -	 * case. | 
|---|
| 242 |  | -	 * | 
|---|
| 243 |  | -	 * Currently, x86_32 with optimize for size (-Os) makes the latest | 
|---|
| 244 |  | -	 * gcc do the above. | 
|---|
| 245 |  | -	 * | 
|---|
| 246 |  | -	 * Note, -mfentry does not use frame pointers, and this test | 
|---|
| 247 |  | -	 *  is not needed if CC_USING_FENTRY is set. | 
|---|
| 248 |  | -	 */ | 
|---|
| 249 |  | -	if (unlikely(current->ret_stack[index].fp != frame_pointer)) { | 
|---|
| 250 |  | -		ftrace_graph_stop(); | 
|---|
| 251 |  | -		WARN(1, "Bad frame pointer: expected %lx, received %lx\n" | 
|---|
| 252 |  | -		     "  from func %ps return to %lx\n", | 
|---|
| 253 |  | -		     current->ret_stack[index].fp, | 
|---|
| 254 |  | -		     frame_pointer, | 
|---|
| 255 |  | -		     (void *)current->ret_stack[index].func, | 
|---|
| 256 |  | -		     current->ret_stack[index].ret); | 
|---|
| 257 |  | -		*ret = (unsigned long)panic; | 
|---|
| 258 |  | -		return; | 
|---|
| 259 |  | -	} | 
|---|
| 260 |  | -#endif | 
|---|
| 261 |  | - | 
|---|
| 262 |  | -	*ret = current->ret_stack[index].ret; | 
|---|
| 263 |  | -	trace->func = current->ret_stack[index].func; | 
|---|
| 264 |  | -	trace->calltime = current->ret_stack[index].calltime; | 
|---|
| 265 |  | -	trace->overrun = atomic_read(¤t->trace_overrun); | 
|---|
| 266 |  | -	trace->depth = current->curr_ret_depth--; | 
|---|
| 267 |  | -	/* | 
|---|
| 268 |  | -	 * We still want to trace interrupts coming in if | 
|---|
| 269 |  | -	 * max_depth is set to 1. Make sure the decrement is | 
|---|
| 270 |  | -	 * seen before ftrace_graph_return. | 
|---|
| 271 |  | -	 */ | 
|---|
| 272 |  | -	barrier(); | 
|---|
| 273 |  | -} | 
|---|
| 274 |  | - | 
|---|
| 275 |  | -/* | 
|---|
| 276 |  | - * Send the trace to the ring-buffer. | 
|---|
| 277 |  | - * @return the original return address. | 
|---|
| 278 |  | - */ | 
|---|
| 279 |  | -unsigned long ftrace_return_to_handler(unsigned long frame_pointer) | 
|---|
| 280 |  | -{ | 
|---|
| 281 |  | -	struct ftrace_graph_ret trace; | 
|---|
| 282 |  | -	unsigned long ret; | 
|---|
| 283 |  | - | 
|---|
| 284 |  | -	ftrace_pop_return_trace(&trace, &ret, frame_pointer); | 
|---|
| 285 |  | -	trace.rettime = trace_clock_local(); | 
|---|
| 286 |  | -	ftrace_graph_return(&trace); | 
|---|
| 287 |  | -	/* | 
|---|
| 288 |  | -	 * The ftrace_graph_return() may still access the current | 
|---|
| 289 |  | -	 * ret_stack structure, we need to make sure the update of | 
|---|
| 290 |  | -	 * curr_ret_stack is after that. | 
|---|
| 291 |  | -	 */ | 
|---|
| 292 |  | -	barrier(); | 
|---|
| 293 |  | -	current->curr_ret_stack--; | 
|---|
| 294 |  | -	/* | 
|---|
| 295 |  | -	 * The curr_ret_stack can be less than -1 only if it was | 
|---|
| 296 |  | -	 * filtered out and it's about to return from the function. | 
|---|
| 297 |  | -	 * Recover the index and continue to trace normal functions. | 
|---|
| 298 |  | -	 */ | 
|---|
| 299 |  | -	if (current->curr_ret_stack < -1) { | 
|---|
| 300 |  | -		current->curr_ret_stack += FTRACE_NOTRACE_DEPTH; | 
|---|
| 301 |  | -		return ret; | 
|---|
| 302 |  | -	} | 
|---|
| 303 |  | - | 
|---|
| 304 |  | -	if (unlikely(!ret)) { | 
|---|
| 305 |  | -		ftrace_graph_stop(); | 
|---|
| 306 |  | -		WARN_ON(1); | 
|---|
| 307 |  | -		/* Might as well panic. What else to do? */ | 
|---|
| 308 |  | -		ret = (unsigned long)panic; | 
|---|
| 309 |  | -	} | 
|---|
| 310 |  | - | 
|---|
| 311 |  | -	return ret; | 
|---|
| 312 |  | -} | 
|---|
| 313 |  | - | 
|---|
| 314 |  | -/** | 
|---|
| 315 |  | - * ftrace_graph_ret_addr - convert a potentially modified stack return address | 
|---|
| 316 |  | - *			   to its original value | 
|---|
| 317 |  | - * | 
|---|
| 318 |  | - * This function can be called by stack unwinding code to convert a found stack | 
|---|
| 319 |  | - * return address ('ret') to its original value, in case the function graph | 
|---|
| 320 |  | - * tracer has modified it to be 'return_to_handler'.  If the address hasn't | 
|---|
| 321 |  | - * been modified, the unchanged value of 'ret' is returned. | 
|---|
| 322 |  | - * | 
|---|
| 323 |  | - * 'idx' is a state variable which should be initialized by the caller to zero | 
|---|
| 324 |  | - * before the first call. | 
|---|
| 325 |  | - * | 
|---|
| 326 |  | - * 'retp' is a pointer to the return address on the stack.  It's ignored if | 
|---|
| 327 |  | - * the arch doesn't have HAVE_FUNCTION_GRAPH_RET_ADDR_PTR defined. | 
|---|
| 328 |  | - */ | 
|---|
| 329 |  | -#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR | 
|---|
| 330 |  | -unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, | 
|---|
| 331 |  | -				    unsigned long ret, unsigned long *retp) | 
|---|
| 332 |  | -{ | 
|---|
| 333 |  | -	int index = task->curr_ret_stack; | 
|---|
| 334 |  | -	int i; | 
|---|
| 335 |  | - | 
|---|
| 336 |  | -	if (ret != (unsigned long)return_to_handler) | 
|---|
| 337 |  | -		return ret; | 
|---|
| 338 |  | - | 
|---|
| 339 |  | -	if (index < -1) | 
|---|
| 340 |  | -		index += FTRACE_NOTRACE_DEPTH; | 
|---|
| 341 |  | - | 
|---|
| 342 |  | -	if (index < 0) | 
|---|
| 343 |  | -		return ret; | 
|---|
| 344 |  | - | 
|---|
| 345 |  | -	for (i = 0; i <= index; i++) | 
|---|
| 346 |  | -		if (task->ret_stack[i].retp == retp) | 
|---|
| 347 |  | -			return task->ret_stack[i].ret; | 
|---|
| 348 |  | - | 
|---|
| 349 |  | -	return ret; | 
|---|
| 350 |  | -} | 
|---|
| 351 |  | -#else /* !HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */ | 
|---|
| 352 |  | -unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, | 
|---|
| 353 |  | -				    unsigned long ret, unsigned long *retp) | 
|---|
| 354 |  | -{ | 
|---|
| 355 |  | -	int task_idx; | 
|---|
| 356 |  | - | 
|---|
| 357 |  | -	if (ret != (unsigned long)return_to_handler) | 
|---|
| 358 |  | -		return ret; | 
|---|
| 359 |  | - | 
|---|
| 360 |  | -	task_idx = task->curr_ret_stack; | 
|---|
| 361 |  | - | 
|---|
| 362 |  | -	if (!task->ret_stack || task_idx < *idx) | 
|---|
| 363 |  | -		return ret; | 
|---|
| 364 |  | - | 
|---|
| 365 |  | -	task_idx -= *idx; | 
|---|
| 366 |  | -	(*idx)++; | 
|---|
| 367 |  | - | 
|---|
| 368 |  | -	return task->ret_stack[task_idx].ret; | 
|---|
| 369 |  | -} | 
|---|
| 370 |  | -#endif /* HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */ | 
|---|
| 371 |  | - | 
|---|
| 372 | 97 | int __trace_graph_entry(struct trace_array *tr, | 
|---|
| 373 | 98 | struct ftrace_graph_ent *trace, | 
|---|
| 374 | 99 | unsigned long flags, | 
|---|
| .. | .. | 
|---|
| 376 | 101 | { | 
|---|
| 377 | 102 | struct trace_event_call *call = &event_funcgraph_entry; | 
|---|
| 378 | 103 | struct ring_buffer_event *event; | 
|---|
| 379 |  | -	struct ring_buffer *buffer = tr->trace_buffer.buffer; | 
|---|
|  | 104 | +	struct trace_buffer *buffer = tr->array_buffer.buffer; | 
|---|
| 380 | 105 | struct ftrace_graph_ent_entry *entry; | 
|---|
| 381 | 106 |  | 
|---|
| 382 | 107 | event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT, | 
|---|
| .. | .. | 
|---|
| 409 | 134 | int cpu; | 
|---|
| 410 | 135 | int pc; | 
|---|
| 411 | 136 |  | 
|---|
|  | 137 | +	if (trace_recursion_test(TRACE_GRAPH_NOTRACE_BIT)) | 
|---|
|  | 138 | +		return 0; | 
|---|
|  | 139 | + | 
|---|
|  | 140 | +	/* | 
|---|
|  | 141 | +	 * Do not trace a function if it's filtered by set_graph_notrace. | 
|---|
|  | 142 | +	 * Make the index of ret stack negative to indicate that it should | 
|---|
|  | 143 | +	 * ignore further functions.  But it needs its own ret stack entry | 
|---|
|  | 144 | +	 * to recover the original index in order to continue tracing after | 
|---|
|  | 145 | +	 * returning from the function. | 
|---|
|  | 146 | +	 */ | 
|---|
|  | 147 | +	if (ftrace_graph_notrace_addr(trace->func)) { | 
|---|
|  | 148 | +		trace_recursion_set(TRACE_GRAPH_NOTRACE_BIT); | 
|---|
|  | 149 | +		/* | 
|---|
|  | 150 | +		 * Need to return 1 to have the return called | 
|---|
|  | 151 | +		 * that will clear the NOTRACE bit. | 
|---|
|  | 152 | +		 */ | 
|---|
|  | 153 | +		return 1; | 
|---|
|  | 154 | +	} | 
|---|
|  | 155 | + | 
|---|
| 412 | 156 | if (!ftrace_trace_task(tr)) | 
|---|
| 413 | 157 | return 0; | 
|---|
| 414 | 158 |  | 
|---|
| .. | .. | 
|---|
| 419 | 163 | return 0; | 
|---|
| 420 | 164 |  | 
|---|
| 421 | 165 | /* | 
|---|
| 422 |  | -	 * Do not trace a function if it's filtered by set_graph_notrace. | 
|---|
| 423 |  | -	 * Make the index of ret stack negative to indicate that it should | 
|---|
| 424 |  | -	 * ignore further functions.  But it needs its own ret stack entry | 
|---|
| 425 |  | -	 * to recover the original index in order to continue tracing after | 
|---|
| 426 |  | -	 * returning from the function. | 
|---|
| 427 |  | -	 */ | 
|---|
| 428 |  | -	if (ftrace_graph_notrace_addr(trace->func)) | 
|---|
| 429 |  | -		return 1; | 
|---|
| 430 |  | - | 
|---|
| 431 |  | -	/* | 
|---|
| 432 | 166 | * Stop here if tracing_threshold is set. We only write function return | 
|---|
| 433 | 167 | * events to the ring buffer. | 
|---|
| 434 | 168 | */ | 
|---|
| .. | .. | 
|---|
| 437 | 171 |  | 
|---|
| 438 | 172 | local_irq_save(flags); | 
|---|
| 439 | 173 | cpu = raw_smp_processor_id(); | 
|---|
| 440 |  | -	data = per_cpu_ptr(tr->trace_buffer.data, cpu); | 
|---|
|  | 174 | +	data = per_cpu_ptr(tr->array_buffer.data, cpu); | 
|---|
| 441 | 175 | disabled = atomic_inc_return(&data->disabled); | 
|---|
| 442 | 176 | if (likely(disabled == 1)) { | 
|---|
| 443 | 177 | pc = preempt_count(); | 
|---|
| .. | .. | 
|---|
| 487 | 221 | { | 
|---|
| 488 | 222 | struct trace_event_call *call = &event_funcgraph_exit; | 
|---|
| 489 | 223 | struct ring_buffer_event *event; | 
|---|
| 490 |  | -	struct ring_buffer *buffer = tr->trace_buffer.buffer; | 
|---|
|  | 224 | +	struct trace_buffer *buffer = tr->array_buffer.buffer; | 
|---|
| 491 | 225 | struct ftrace_graph_ret_entry *entry; | 
|---|
| 492 | 226 |  | 
|---|
| 493 | 227 | event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_RET, | 
|---|
| .. | .. | 
|---|
| 511 | 245 |  | 
|---|
| 512 | 246 | ftrace_graph_addr_finish(trace); | 
|---|
| 513 | 247 |  | 
|---|
|  | 248 | +	if (trace_recursion_test(TRACE_GRAPH_NOTRACE_BIT)) { | 
|---|
|  | 249 | +		trace_recursion_clear(TRACE_GRAPH_NOTRACE_BIT); | 
|---|
|  | 250 | +		return; | 
|---|
|  | 251 | +	} | 
|---|
|  | 252 | + | 
|---|
| 514 | 253 | local_irq_save(flags); | 
|---|
| 515 | 254 | cpu = raw_smp_processor_id(); | 
|---|
| 516 |  | -	data = per_cpu_ptr(tr->trace_buffer.data, cpu); | 
|---|
|  | 255 | +	data = per_cpu_ptr(tr->array_buffer.data, cpu); | 
|---|
| 517 | 256 | disabled = atomic_inc_return(&data->disabled); | 
|---|
| 518 | 257 | if (likely(disabled == 1)) { | 
|---|
| 519 | 258 | pc = preempt_count(); | 
|---|
| .. | .. | 
|---|
| 536 | 275 | { | 
|---|
| 537 | 276 | ftrace_graph_addr_finish(trace); | 
|---|
| 538 | 277 |  | 
|---|
|  | 278 | +	if (trace_recursion_test(TRACE_GRAPH_NOTRACE_BIT)) { | 
|---|
|  | 279 | +		trace_recursion_clear(TRACE_GRAPH_NOTRACE_BIT); | 
|---|
|  | 280 | +		return; | 
|---|
|  | 281 | +	} | 
|---|
|  | 282 | + | 
|---|
| 539 | 283 | if (tracing_thresh && | 
|---|
| 540 | 284 | (trace->rettime - trace->calltime < tracing_thresh)) | 
|---|
| 541 | 285 | return; | 
|---|
| .. | .. | 
|---|
| 543 | 287 | trace_graph_return(trace); | 
|---|
| 544 | 288 | } | 
|---|
| 545 | 289 |  | 
|---|
|  | 290 | +static struct fgraph_ops funcgraph_thresh_ops = { | 
|---|
|  | 291 | +	.entryfunc = &trace_graph_entry, | 
|---|
|  | 292 | +	.retfunc = &trace_graph_thresh_return, | 
|---|
|  | 293 | +}; | 
|---|
|  | 294 | + | 
|---|
|  | 295 | +static struct fgraph_ops funcgraph_ops = { | 
|---|
|  | 296 | +	.entryfunc = &trace_graph_entry, | 
|---|
|  | 297 | +	.retfunc = &trace_graph_return, | 
|---|
|  | 298 | +}; | 
|---|
|  | 299 | + | 
|---|
| 546 | 300 | static int graph_trace_init(struct trace_array *tr) | 
|---|
| 547 | 301 | { | 
|---|
| 548 | 302 | int ret; | 
|---|
| 549 | 303 |  | 
|---|
| 550 | 304 | set_graph_array(tr); | 
|---|
| 551 | 305 | if (tracing_thresh) | 
|---|
| 552 |  | -		ret = register_ftrace_graph(&trace_graph_thresh_return, | 
|---|
| 553 |  | -					    &trace_graph_entry); | 
|---|
|  | 306 | +		ret = register_ftrace_graph(&funcgraph_thresh_ops); | 
|---|
| 554 | 307 | else | 
|---|
| 555 |  | -		ret = register_ftrace_graph(&trace_graph_return, | 
|---|
| 556 |  | -					    &trace_graph_entry); | 
|---|
|  | 308 | +		ret = register_ftrace_graph(&funcgraph_ops); | 
|---|
| 557 | 309 | if (ret) | 
|---|
| 558 | 310 | return ret; | 
|---|
| 559 | 311 | tracing_start_cmdline_record(); | 
|---|
| .. | .. | 
|---|
| 564 | 316 | static void graph_trace_reset(struct trace_array *tr) | 
|---|
| 565 | 317 | { | 
|---|
| 566 | 318 | tracing_stop_cmdline_record(); | 
|---|
| 567 |  | -	unregister_ftrace_graph(); | 
|---|
|  | 319 | +	if (tracing_thresh) | 
|---|
|  | 320 | +		unregister_ftrace_graph(&funcgraph_thresh_ops); | 
|---|
|  | 321 | +	else | 
|---|
|  | 322 | +		unregister_ftrace_graph(&funcgraph_ops); | 
|---|
| 568 | 323 | } | 
|---|
| 569 | 324 |  | 
|---|
| 570 | 325 | static int graph_trace_update_thresh(struct trace_array *tr) | 
|---|
| .. | .. | 
|---|
| 622 | 377 | { | 
|---|
| 623 | 378 | trace_seq_putc(s, ' '); | 
|---|
| 624 | 379 | trace_print_lat_fmt(s, entry); | 
|---|
|  | 380 | +	trace_seq_puts(s, " | "); | 
|---|
| 625 | 381 | } | 
|---|
| 626 | 382 |  | 
|---|
| 627 | 383 | /* If the pid changed since the last trace, output this event */ | 
|---|
| .. | .. | 
|---|
| 688 | 444 | * We need to consume the current entry to see | 
|---|
| 689 | 445 | * the next one. | 
|---|
| 690 | 446 | */ | 
|---|
| 691 |  | -			ring_buffer_consume(iter->trace_buffer->buffer, iter->cpu, | 
|---|
|  | 447 | +			ring_buffer_consume(iter->array_buffer->buffer, iter->cpu, | 
|---|
| 692 | 448 | NULL, NULL); | 
|---|
| 693 |  | -			event = ring_buffer_peek(iter->trace_buffer->buffer, iter->cpu, | 
|---|
|  | 449 | +			event = ring_buffer_peek(iter->array_buffer->buffer, iter->cpu, | 
|---|
| 694 | 450 | NULL, NULL); | 
|---|
| 695 | 451 | } | 
|---|
| 696 | 452 |  | 
|---|
| .. | .. | 
|---|
| 726 | 482 |  | 
|---|
| 727 | 483 | /* this is a leaf, now advance the iterator */ | 
|---|
| 728 | 484 | if (ring_iter) | 
|---|
| 729 |  | -		ring_buffer_read(ring_iter, NULL); | 
|---|
|  | 485 | +		ring_buffer_iter_advance(ring_iter); | 
|---|
| 730 | 486 |  | 
|---|
| 731 | 487 | return next; | 
|---|
| 732 | 488 | } | 
|---|
| .. | .. | 
|---|
| 740 | 496 |  | 
|---|
| 741 | 497 | trace_seq_printf(s, "%5lu.%06lu |  ", | 
|---|
| 742 | 498 | (unsigned long)t, usecs_rem); | 
|---|
|  | 499 | +} | 
|---|
|  | 500 | + | 
|---|
|  | 501 | +static void | 
|---|
|  | 502 | +print_graph_rel_time(struct trace_iterator *iter, struct trace_seq *s) | 
|---|
|  | 503 | +{ | 
|---|
|  | 504 | +	unsigned long long usecs; | 
|---|
|  | 505 | + | 
|---|
|  | 506 | +	usecs = iter->ts - iter->array_buffer->time_start; | 
|---|
|  | 507 | +	do_div(usecs, NSEC_PER_USEC); | 
|---|
|  | 508 | + | 
|---|
|  | 509 | +	trace_seq_printf(s, "%9llu us |  ", usecs); | 
|---|
| 743 | 510 | } | 
|---|
| 744 | 511 |  | 
|---|
| 745 | 512 | static void | 
|---|
| .. | .. | 
|---|
| 758 | 525 | /* Absolute time */ | 
|---|
| 759 | 526 | if (flags & TRACE_GRAPH_PRINT_ABS_TIME) | 
|---|
| 760 | 527 | print_graph_abs_time(iter->ts, s); | 
|---|
|  | 528 | + | 
|---|
|  | 529 | +		/* Relative time */ | 
|---|
|  | 530 | +		if (flags & TRACE_GRAPH_PRINT_REL_TIME) | 
|---|
|  | 531 | +			print_graph_rel_time(iter, s); | 
|---|
| 761 | 532 |  | 
|---|
| 762 | 533 | /* Cpu */ | 
|---|
| 763 | 534 | if (flags & TRACE_GRAPH_PRINT_CPU) | 
|---|
| .. | .. | 
|---|
| 874 | 645 |  | 
|---|
| 875 | 646 | cpu_data = per_cpu_ptr(data->cpu_data, cpu); | 
|---|
| 876 | 647 |  | 
|---|
| 877 |  | -		/* If a graph tracer ignored set_graph_notrace */ | 
|---|
| 878 |  | -		if (call->depth < -1) | 
|---|
| 879 |  | -			call->depth += FTRACE_NOTRACE_DEPTH; | 
|---|
| 880 |  | - | 
|---|
| 881 | 648 | /* | 
|---|
| 882 | 649 | * Comments display at + 1 to depth. Since | 
|---|
| 883 | 650 | * this is a leaf function, keep the comments | 
|---|
| .. | .. | 
|---|
| 919 | 686 | if (data) { | 
|---|
| 920 | 687 | struct fgraph_cpu_data *cpu_data; | 
|---|
| 921 | 688 | int cpu = iter->cpu; | 
|---|
| 922 |  | - | 
|---|
| 923 |  | -		/* If a graph tracer ignored set_graph_notrace */ | 
|---|
| 924 |  | -		if (call->depth < -1) | 
|---|
| 925 |  | -			call->depth += FTRACE_NOTRACE_DEPTH; | 
|---|
| 926 | 689 |  | 
|---|
| 927 | 690 | cpu_data = per_cpu_ptr(data->cpu_data, cpu); | 
|---|
| 928 | 691 | cpu_data->depth = call->depth; | 
|---|
| .. | .. | 
|---|
| 974 | 737 | /* Absolute time */ | 
|---|
| 975 | 738 | if (flags & TRACE_GRAPH_PRINT_ABS_TIME) | 
|---|
| 976 | 739 | print_graph_abs_time(iter->ts, s); | 
|---|
|  | 740 | + | 
|---|
|  | 741 | +	/* Relative time */ | 
|---|
|  | 742 | +	if (flags & TRACE_GRAPH_PRINT_REL_TIME) | 
|---|
|  | 743 | +		print_graph_rel_time(iter, s); | 
|---|
| 977 | 744 |  | 
|---|
| 978 | 745 | /* Cpu */ | 
|---|
| 979 | 746 | if (flags & TRACE_GRAPH_PRINT_CPU) | 
|---|
| .. | .. | 
|---|
| 1351 | 1118 |  | 
|---|
| 1352 | 1119 | if (flags & TRACE_GRAPH_PRINT_ABS_TIME) | 
|---|
| 1353 | 1120 | size += 16; | 
|---|
|  | 1121 | +	if (flags & TRACE_GRAPH_PRINT_REL_TIME) | 
|---|
|  | 1122 | +		size += 16; | 
|---|
| 1354 | 1123 | if (flags & TRACE_GRAPH_PRINT_CPU) | 
|---|
| 1355 | 1124 | size += 4; | 
|---|
| 1356 | 1125 | if (flags & TRACE_GRAPH_PRINT_PROC) | 
|---|
| .. | .. | 
|---|
| 1375 | 1144 | seq_putc(s, '#'); | 
|---|
| 1376 | 1145 | if (flags & TRACE_GRAPH_PRINT_ABS_TIME) | 
|---|
| 1377 | 1146 | seq_puts(s, "     TIME       "); | 
|---|
|  | 1147 | +	if (flags & TRACE_GRAPH_PRINT_REL_TIME) | 
|---|
|  | 1148 | +		seq_puts(s, "   REL TIME     "); | 
|---|
| 1378 | 1149 | if (flags & TRACE_GRAPH_PRINT_CPU) | 
|---|
| 1379 | 1150 | seq_puts(s, " CPU"); | 
|---|
| 1380 | 1151 | if (flags & TRACE_GRAPH_PRINT_PROC) | 
|---|
| 1381 | 1152 | seq_puts(s, "  TASK/PID       "); | 
|---|
| 1382 | 1153 | if (lat) | 
|---|
| 1383 |  | -		seq_puts(s, "||||"); | 
|---|
|  | 1154 | +		seq_puts(s, "||||   "); | 
|---|
| 1384 | 1155 | if (flags & TRACE_GRAPH_PRINT_DURATION) | 
|---|
| 1385 | 1156 | seq_puts(s, "  DURATION   "); | 
|---|
| 1386 | 1157 | seq_puts(s, "               FUNCTION CALLS\n"); | 
|---|
| .. | .. | 
|---|
| 1389 | 1160 | seq_putc(s, '#'); | 
|---|
| 1390 | 1161 | if (flags & TRACE_GRAPH_PRINT_ABS_TIME) | 
|---|
| 1391 | 1162 | seq_puts(s, "      |         "); | 
|---|
|  | 1163 | +	if (flags & TRACE_GRAPH_PRINT_REL_TIME) | 
|---|
|  | 1164 | +		seq_puts(s, "      |         "); | 
|---|
| 1392 | 1165 | if (flags & TRACE_GRAPH_PRINT_CPU) | 
|---|
| 1393 | 1166 | seq_puts(s, " |  "); | 
|---|
| 1394 | 1167 | if (flags & TRACE_GRAPH_PRINT_PROC) | 
|---|
| 1395 | 1168 | seq_puts(s, "   |    |        "); | 
|---|
| 1396 | 1169 | if (lat) | 
|---|
| 1397 |  | -		seq_puts(s, "||||"); | 
|---|
|  | 1170 | +		seq_puts(s, "||||   "); | 
|---|
| 1398 | 1171 | if (flags & TRACE_GRAPH_PRINT_DURATION) | 
|---|
| 1399 | 1172 | seq_puts(s, "   |   |      "); | 
|---|
| 1400 | 1173 | seq_puts(s, "               |   |   |   |\n"); | 
|---|
| .. | .. | 
|---|
| 1563 | 1336 |  | 
|---|
| 1564 | 1337 | static __init int init_graph_tracefs(void) | 
|---|
| 1565 | 1338 | { | 
|---|
| 1566 |  | -	struct dentry *d_tracer; | 
|---|
|  | 1339 | +	int ret; | 
|---|
| 1567 | 1340 |  | 
|---|
| 1568 |  | -	d_tracer = tracing_init_dentry(); | 
|---|
| 1569 |  | -	if (IS_ERR(d_tracer)) | 
|---|
|  | 1341 | +	ret = tracing_init_dentry(); | 
|---|
|  | 1342 | +	if (ret) | 
|---|
| 1570 | 1343 | return 0; | 
|---|
| 1571 | 1344 |  | 
|---|
| 1572 |  | -	trace_create_file("max_graph_depth", 0644, d_tracer, | 
|---|
|  | 1345 | +	trace_create_file("max_graph_depth", 0644, NULL, | 
|---|
| 1573 | 1346 | NULL, &graph_depth_fops); | 
|---|
| 1574 | 1347 |  | 
|---|
| 1575 | 1348 | return 0; | 
|---|