LCOV - code coverage report
Current view: top level - kernel/trace - fgraph.c (source / functions) Hit Total Coverage
Test: Real Lines: 18 170 10.6 %
Date: 2020-10-17 15:46:16 Functions: 0 20 0.0 %
Legend: Neither, QEMU, Real, Both Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0
       2                 :            : /*
       3                 :            :  * Infrastructure to took into function calls and returns.
       4                 :            :  * Copyright (c) 2008-2009 Frederic Weisbecker <fweisbec@gmail.com>
       5                 :            :  * Mostly borrowed from function tracer which
       6                 :            :  * is Copyright (c) Steven Rostedt <srostedt@redhat.com>
       7                 :            :  *
       8                 :            :  * Highly modified by Steven Rostedt (VMware).
       9                 :            :  */
      10                 :            : #include <linux/suspend.h>
      11                 :            : #include <linux/ftrace.h>
      12                 :            : #include <linux/slab.h>
      13                 :            : 
      14                 :            : #include <trace/events/sched.h>
      15                 :            : 
      16                 :            : #include "ftrace_internal.h"
      17                 :            : 
      18                 :            : #ifdef CONFIG_DYNAMIC_FTRACE
      19                 :            : #define ASSIGN_OPS_HASH(opsname, val) \
      20                 :            :         .func_hash              = val, \
      21                 :            :         .local_hash.regex_lock  = __MUTEX_INITIALIZER(opsname.local_hash.regex_lock),
      22                 :            : #else
      23                 :            : #define ASSIGN_OPS_HASH(opsname, val)
      24                 :            : #endif
      25                 :            : 
      26                 :            : static bool kill_ftrace_graph;
      27                 :            : int ftrace_graph_active;
      28                 :            : 
      29                 :            : /* Both enabled by default (can be cleared by function_graph tracer flags */
      30                 :            : static bool fgraph_sleep_time = true;
      31                 :            : 
      32                 :            : /**
      33                 :            :  * ftrace_graph_is_dead - returns true if ftrace_graph_stop() was called
      34                 :            :  *
      35                 :            :  * ftrace_graph_stop() is called when a severe error is detected in
      36                 :            :  * the function graph tracing. This function is called by the critical
      37                 :            :  * paths of function graph to keep those paths from doing any more harm.
      38                 :            :  */
      39                 :          0 : bool ftrace_graph_is_dead(void)
      40                 :            : {
      41                 :          0 :         return kill_ftrace_graph;
      42                 :            : }
      43                 :            : 
      44                 :            : /**
      45                 :            :  * ftrace_graph_stop - set to permanently disable function graph tracincg
      46                 :            :  *
      47                 :            :  * In case of an error int function graph tracing, this is called
      48                 :            :  * to try to keep function graph tracing from causing any more harm.
      49                 :            :  * Usually this is pretty severe and this is called to try to at least
      50                 :            :  * get a warning out to the user.
      51                 :            :  */
      52                 :          0 : void ftrace_graph_stop(void)
      53                 :            : {
      54                 :          0 :         kill_ftrace_graph = true;
      55                 :          0 : }
      56                 :            : 
      57                 :            : /* Add a function return address to the trace stack on thread info.*/
      58                 :            : static int
      59                 :          0 : ftrace_push_return_trace(unsigned long ret, unsigned long func,
      60                 :            :                          unsigned long frame_pointer, unsigned long *retp)
      61                 :            : {
      62                 :            :         unsigned long long calltime;
      63                 :            :         int index;
      64                 :            : 
      65                 :          0 :         if (unlikely(ftrace_graph_is_dead()))
      66                 :            :                 return -EBUSY;
      67                 :            : 
      68                 :          0 :         if (!current->ret_stack)
      69                 :            :                 return -EBUSY;
      70                 :            : 
      71                 :            :         /*
      72                 :            :          * We must make sure the ret_stack is tested before we read
      73                 :            :          * anything else.
      74                 :            :          */
      75                 :          0 :         smp_rmb();
      76                 :            : 
      77                 :            :         /* The return trace stack is full */
      78                 :          0 :         if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) {
      79                 :          0 :                 atomic_inc(&current->trace_overrun);
      80                 :          0 :                 return -EBUSY;
      81                 :            :         }
      82                 :            : 
      83                 :          0 :         calltime = trace_clock_local();
      84                 :            : 
      85                 :          0 :         index = ++current->curr_ret_stack;
      86                 :          0 :         barrier();
      87                 :          0 :         current->ret_stack[index].ret = ret;
      88                 :          0 :         current->ret_stack[index].func = func;
      89                 :          0 :         current->ret_stack[index].calltime = calltime;
      90                 :            : #ifdef HAVE_FUNCTION_GRAPH_FP_TEST
      91                 :            :         current->ret_stack[index].fp = frame_pointer;
      92                 :            : #endif
      93                 :            : #ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
      94                 :            :         current->ret_stack[index].retp = retp;
      95                 :            : #endif
      96                 :          0 :         return 0;
      97                 :            : }
      98                 :            : 
      99                 :          0 : int function_graph_enter(unsigned long ret, unsigned long func,
     100                 :            :                          unsigned long frame_pointer, unsigned long *retp)
     101                 :            : {
     102                 :            :         struct ftrace_graph_ent trace;
     103                 :            : 
     104                 :          0 :         trace.func = func;
     105                 :          0 :         trace.depth = ++current->curr_ret_depth;
     106                 :            : 
     107                 :          0 :         if (ftrace_push_return_trace(ret, func, frame_pointer, retp))
     108                 :            :                 goto out;
     109                 :            : 
     110                 :            :         /* Only trace if the calling function expects to */
     111                 :          0 :         if (!ftrace_graph_entry(&trace))
     112                 :            :                 goto out_ret;
     113                 :            : 
     114                 :            :         return 0;
     115                 :            :  out_ret:
     116                 :          0 :         current->curr_ret_stack--;
     117                 :            :  out:
     118                 :          0 :         current->curr_ret_depth--;
     119                 :          0 :         return -EBUSY;
     120                 :            : }
     121                 :            : 
     122                 :            : /* Retrieve a function return address to the trace stack on thread info.*/
     123                 :            : static void
     124                 :          0 : ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret,
     125                 :            :                         unsigned long frame_pointer)
     126                 :            : {
     127                 :            :         int index;
     128                 :            : 
     129                 :          0 :         index = current->curr_ret_stack;
     130                 :            : 
     131                 :          0 :         if (unlikely(index < 0 || index >= FTRACE_RETFUNC_DEPTH)) {
     132                 :            :                 ftrace_graph_stop();
     133                 :          0 :                 WARN_ON(1);
     134                 :            :                 /* Might as well panic, otherwise we have no where to go */
     135                 :          0 :                 *ret = (unsigned long)panic;
     136                 :          0 :                 return;
     137                 :            :         }
     138                 :            : 
     139                 :            : #ifdef HAVE_FUNCTION_GRAPH_FP_TEST
     140                 :            :         /*
     141                 :            :          * The arch may choose to record the frame pointer used
     142                 :            :          * and check it here to make sure that it is what we expect it
     143                 :            :          * to be. If gcc does not set the place holder of the return
     144                 :            :          * address in the frame pointer, and does a copy instead, then
     145                 :            :          * the function graph trace will fail. This test detects this
     146                 :            :          * case.
     147                 :            :          *
     148                 :            :          * Currently, x86_32 with optimize for size (-Os) makes the latest
     149                 :            :          * gcc do the above.
     150                 :            :          *
     151                 :            :          * Note, -mfentry does not use frame pointers, and this test
     152                 :            :          *  is not needed if CC_USING_FENTRY is set.
     153                 :            :          */
     154                 :            :         if (unlikely(current->ret_stack[index].fp != frame_pointer)) {
     155                 :            :                 ftrace_graph_stop();
     156                 :            :                 WARN(1, "Bad frame pointer: expected %lx, received %lx\n"
     157                 :            :                      "  from func %ps return to %lx\n",
     158                 :            :                      current->ret_stack[index].fp,
     159                 :            :                      frame_pointer,
     160                 :            :                      (void *)current->ret_stack[index].func,
     161                 :            :                      current->ret_stack[index].ret);
     162                 :            :                 *ret = (unsigned long)panic;
     163                 :            :                 return;
     164                 :            :         }
     165                 :            : #endif
     166                 :            : 
     167                 :          0 :         *ret = current->ret_stack[index].ret;
     168                 :          0 :         trace->func = current->ret_stack[index].func;
     169                 :          0 :         trace->calltime = current->ret_stack[index].calltime;
     170                 :          0 :         trace->overrun = atomic_read(&current->trace_overrun);
     171                 :          0 :         trace->depth = current->curr_ret_depth--;
     172                 :            :         /*
     173                 :            :          * We still want to trace interrupts coming in if
     174                 :            :          * max_depth is set to 1. Make sure the decrement is
     175                 :            :          * seen before ftrace_graph_return.
     176                 :            :          */
     177                 :          0 :         barrier();
     178                 :            : }
     179                 :            : 
     180                 :            : /*
     181                 :            :  * Hibernation protection.
     182                 :            :  * The state of the current task is too much unstable during
     183                 :            :  * suspend/restore to disk. We want to protect against that.
     184                 :            :  */
     185                 :            : static int
     186                 :            : ftrace_suspend_notifier_call(struct notifier_block *bl, unsigned long state,
     187                 :            :                                                         void *unused)
     188                 :            : {
     189                 :            :         switch (state) {
     190                 :            :         case PM_HIBERNATION_PREPARE:
     191                 :            :                 pause_graph_tracing();
     192                 :            :                 break;
     193                 :            : 
     194                 :            :         case PM_POST_HIBERNATION:
     195                 :            :                 unpause_graph_tracing();
     196                 :            :                 break;
     197                 :            :         }
     198                 :            :         return NOTIFY_DONE;
     199                 :            : }
     200                 :            : 
     201                 :            : static struct notifier_block ftrace_suspend_notifier = {
     202                 :            :         .notifier_call = ftrace_suspend_notifier_call,
     203                 :            : };
     204                 :            : 
     205                 :            : /*
     206                 :            :  * Send the trace to the ring-buffer.
     207                 :            :  * @return the original return address.
     208                 :            :  */
     209                 :          0 : unsigned long ftrace_return_to_handler(unsigned long frame_pointer)
     210                 :            : {
     211                 :            :         struct ftrace_graph_ret trace;
     212                 :            :         unsigned long ret;
     213                 :            : 
     214                 :          0 :         ftrace_pop_return_trace(&trace, &ret, frame_pointer);
     215                 :          0 :         trace.rettime = trace_clock_local();
     216                 :          0 :         ftrace_graph_return(&trace);
     217                 :            :         /*
     218                 :            :          * The ftrace_graph_return() may still access the current
     219                 :            :          * ret_stack structure, we need to make sure the update of
     220                 :            :          * curr_ret_stack is after that.
     221                 :            :          */
     222                 :          0 :         barrier();
     223                 :          0 :         current->curr_ret_stack--;
     224                 :            : 
     225                 :          0 :         if (unlikely(!ret)) {
     226                 :            :                 ftrace_graph_stop();
     227                 :          0 :                 WARN_ON(1);
     228                 :            :                 /* Might as well panic. What else to do? */
     229                 :          0 :                 ret = (unsigned long)panic;
     230                 :            :         }
     231                 :            : 
     232                 :          0 :         return ret;
     233                 :            : }
     234                 :            : 
     235                 :            : /**
     236                 :            :  * ftrace_graph_get_ret_stack - return the entry of the shadow stack
     237                 :            :  * @task: The task to read the shadow stack from
     238                 :            :  * @idx: Index down the shadow stack
     239                 :            :  *
     240                 :            :  * Return the ret_struct on the shadow stack of the @task at the
     241                 :            :  * call graph at @idx starting with zero. If @idx is zero, it
     242                 :            :  * will return the last saved ret_stack entry. If it is greater than
     243                 :            :  * zero, it will return the corresponding ret_stack for the depth
     244                 :            :  * of saved return addresses.
     245                 :            :  */
     246                 :            : struct ftrace_ret_stack *
     247                 :          0 : ftrace_graph_get_ret_stack(struct task_struct *task, int idx)
     248                 :            : {
     249                 :          0 :         idx = task->curr_ret_stack - idx;
     250                 :            : 
     251                 :          0 :         if (idx >= 0 && idx <= task->curr_ret_stack)
     252                 :          0 :                 return &task->ret_stack[idx];
     253                 :            : 
     254                 :            :         return NULL;
     255                 :            : }
     256                 :            : 
     257                 :            : /**
     258                 :            :  * ftrace_graph_ret_addr - convert a potentially modified stack return address
     259                 :            :  *                         to its original value
     260                 :            :  *
     261                 :            :  * This function can be called by stack unwinding code to convert a found stack
     262                 :            :  * return address ('ret') to its original value, in case the function graph
     263                 :            :  * tracer has modified it to be 'return_to_handler'.  If the address hasn't
     264                 :            :  * been modified, the unchanged value of 'ret' is returned.
     265                 :            :  *
     266                 :            :  * 'idx' is a state variable which should be initialized by the caller to zero
     267                 :            :  * before the first call.
     268                 :            :  *
     269                 :            :  * 'retp' is a pointer to the return address on the stack.  It's ignored if
     270                 :            :  * the arch doesn't have HAVE_FUNCTION_GRAPH_RET_ADDR_PTR defined.
     271                 :            :  */
     272                 :            : #ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
     273                 :            : unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx,
     274                 :            :                                     unsigned long ret, unsigned long *retp)
     275                 :            : {
     276                 :            :         int index = task->curr_ret_stack;
     277                 :            :         int i;
     278                 :            : 
     279                 :            :         if (ret != (unsigned long)dereference_kernel_function_descriptor(return_to_handler))
     280                 :            :                 return ret;
     281                 :            : 
     282                 :            :         if (index < 0)
     283                 :            :                 return ret;
     284                 :            : 
     285                 :            :         for (i = 0; i <= index; i++)
     286                 :            :                 if (task->ret_stack[i].retp == retp)
     287                 :            :                         return task->ret_stack[i].ret;
     288                 :            : 
     289                 :            :         return ret;
     290                 :            : }
     291                 :            : #else /* !HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */
     292                 :          0 : unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx,
     293                 :            :                                     unsigned long ret, unsigned long *retp)
     294                 :            : {
     295                 :            :         int task_idx;
     296                 :            : 
     297                 :          0 :         if (ret != (unsigned long)dereference_kernel_function_descriptor(return_to_handler))
     298                 :            :                 return ret;
     299                 :            : 
     300                 :          0 :         task_idx = task->curr_ret_stack;
     301                 :            : 
     302                 :          0 :         if (!task->ret_stack || task_idx < *idx)
     303                 :            :                 return ret;
     304                 :            : 
     305                 :          0 :         task_idx -= *idx;
     306                 :          0 :         (*idx)++;
     307                 :            : 
     308                 :          0 :         return task->ret_stack[task_idx].ret;
     309                 :            : }
     310                 :            : #endif /* HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */
     311                 :            : 
     312                 :            : static struct ftrace_ops graph_ops = {
     313                 :            :         .func                   = ftrace_stub,
     314                 :            :         .flags                  = FTRACE_OPS_FL_RECURSION_SAFE |
     315                 :            :                                    FTRACE_OPS_FL_INITIALIZED |
     316                 :            :                                    FTRACE_OPS_FL_PID |
     317                 :            :                                    FTRACE_OPS_FL_STUB,
     318                 :            : #ifdef FTRACE_GRAPH_TRAMP_ADDR
     319                 :            :         .trampoline             = FTRACE_GRAPH_TRAMP_ADDR,
     320                 :            :         /* trampoline_size is only needed for dynamically allocated tramps */
     321                 :            : #endif
     322                 :            :         ASSIGN_OPS_HASH(graph_ops, &global_ops.local_hash)
     323                 :            : };
     324                 :            : 
     325                 :          0 : void ftrace_graph_sleep_time_control(bool enable)
     326                 :            : {
     327                 :          0 :         fgraph_sleep_time = enable;
     328                 :          0 : }
     329                 :            : 
     330                 :          0 : int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)
     331                 :            : {
     332                 :          0 :         return 0;
     333                 :            : }
     334                 :            : 
     335                 :            : /* The callbacks that hook a function */
     336                 :            : trace_func_graph_ret_t ftrace_graph_return =
     337                 :            :                         (trace_func_graph_ret_t)ftrace_stub;
     338                 :            : trace_func_graph_ent_t ftrace_graph_entry = ftrace_graph_entry_stub;
     339                 :            : static trace_func_graph_ent_t __ftrace_graph_entry = ftrace_graph_entry_stub;
     340                 :            : 
     341                 :            : /* Try to assign a return stack array on FTRACE_RETSTACK_ALLOC_SIZE tasks. */
     342                 :          0 : static int alloc_retstack_tasklist(struct ftrace_ret_stack **ret_stack_list)
     343                 :            : {
     344                 :            :         int i;
     345                 :            :         int ret = 0;
     346                 :            :         int start = 0, end = FTRACE_RETSTACK_ALLOC_SIZE;
     347                 :            :         struct task_struct *g, *t;
     348                 :            : 
     349                 :          0 :         for (i = 0; i < FTRACE_RETSTACK_ALLOC_SIZE; i++) {
     350                 :          0 :                 ret_stack_list[i] =
     351                 :          0 :                         kmalloc_array(FTRACE_RETFUNC_DEPTH,
     352                 :            :                                       sizeof(struct ftrace_ret_stack),
     353                 :            :                                       GFP_KERNEL);
     354                 :          0 :                 if (!ret_stack_list[i]) {
     355                 :            :                         start = 0;
     356                 :          0 :                         end = i;
     357                 :            :                         ret = -ENOMEM;
     358                 :          0 :                         goto free;
     359                 :            :                 }
     360                 :            :         }
     361                 :            : 
     362                 :          0 :         read_lock(&tasklist_lock);
     363                 :          0 :         do_each_thread(g, t) {
     364                 :          0 :                 if (start == end) {
     365                 :            :                         ret = -EAGAIN;
     366                 :            :                         goto unlock;
     367                 :            :                 }
     368                 :            : 
     369                 :          0 :                 if (t->ret_stack == NULL) {
     370                 :            :                         atomic_set(&t->tracing_graph_pause, 0);
     371                 :            :                         atomic_set(&t->trace_overrun, 0);
     372                 :          0 :                         t->curr_ret_stack = -1;
     373                 :          0 :                         t->curr_ret_depth = -1;
     374                 :            :                         /* Make sure the tasks see the -1 first: */
     375                 :          0 :                         smp_wmb();
     376                 :          0 :                         t->ret_stack = ret_stack_list[start++];
     377                 :            :                 }
     378                 :          0 :         } while_each_thread(g, t);
     379                 :            : 
     380                 :            : unlock:
     381                 :            :         read_unlock(&tasklist_lock);
     382                 :            : free:
     383                 :          0 :         for (i = start; i < end; i++)
     384                 :          0 :                 kfree(ret_stack_list[i]);
     385                 :          0 :         return ret;
     386                 :            : }
     387                 :            : 
     388                 :            : static void
     389                 :          0 : ftrace_graph_probe_sched_switch(void *ignore, bool preempt,
     390                 :            :                         struct task_struct *prev, struct task_struct *next)
     391                 :            : {
     392                 :            :         unsigned long long timestamp;
     393                 :            :         int index;
     394                 :            : 
     395                 :            :         /*
     396                 :            :          * Does the user want to count the time a function was asleep.
     397                 :            :          * If so, do not update the time stamps.
     398                 :            :          */
     399                 :          0 :         if (fgraph_sleep_time)
     400                 :            :                 return;
     401                 :            : 
     402                 :          0 :         timestamp = trace_clock_local();
     403                 :            : 
     404                 :          0 :         prev->ftrace_timestamp = timestamp;
     405                 :            : 
     406                 :            :         /* only process tasks that we timestamped */
     407                 :          0 :         if (!next->ftrace_timestamp)
     408                 :            :                 return;
     409                 :            : 
     410                 :            :         /*
     411                 :            :          * Update all the counters in next to make up for the
     412                 :            :          * time next was sleeping.
     413                 :            :          */
     414                 :          0 :         timestamp -= next->ftrace_timestamp;
     415                 :            : 
     416                 :          0 :         for (index = next->curr_ret_stack; index >= 0; index--)
     417                 :          0 :                 next->ret_stack[index].calltime += timestamp;
     418                 :            : }
     419                 :            : 
     420                 :          0 : static int ftrace_graph_entry_test(struct ftrace_graph_ent *trace)
     421                 :            : {
     422                 :          0 :         if (!ftrace_ops_test(&global_ops, trace->func, NULL))
     423                 :            :                 return 0;
     424                 :          0 :         return __ftrace_graph_entry(trace);
     425                 :            : }
     426                 :            : 
     427                 :            : /*
     428                 :            :  * The function graph tracer should only trace the functions defined
     429                 :            :  * by set_ftrace_filter and set_ftrace_notrace. If another function
     430                 :            :  * tracer ops is registered, the graph tracer requires testing the
     431                 :            :  * function against the global ops, and not just trace any function
     432                 :            :  * that any ftrace_ops registered.
     433                 :            :  */
     434                 :          0 : void update_function_graph_func(void)
     435                 :            : {
     436                 :            :         struct ftrace_ops *op;
     437                 :            :         bool do_test = false;
     438                 :            : 
     439                 :            :         /*
     440                 :            :          * The graph and global ops share the same set of functions
     441                 :            :          * to test. If any other ops is on the list, then
     442                 :            :          * the graph tracing needs to test if its the function
     443                 :            :          * it should call.
     444                 :            :          */
     445                 :          0 :         do_for_each_ftrace_op(op, ftrace_ops_list) {
     446                 :          0 :                 if (op != &global_ops && op != &graph_ops &&
     447                 :            :                     op != &ftrace_list_end) {
     448                 :            :                         do_test = true;
     449                 :            :                         /* in double loop, break out with goto */
     450                 :            :                         goto out;
     451                 :            :                 }
     452                 :          0 :         } while_for_each_ftrace_op(op);
     453                 :            :  out:
     454                 :          0 :         if (do_test)
     455                 :          0 :                 ftrace_graph_entry = ftrace_graph_entry_test;
     456                 :            :         else
     457                 :          0 :                 ftrace_graph_entry = __ftrace_graph_entry;
     458                 :          0 : }
     459                 :            : 
     460                 :            : static DEFINE_PER_CPU(struct ftrace_ret_stack *, idle_ret_stack);
     461                 :            : 
     462                 :            : static void
     463                 :            : graph_init_task(struct task_struct *t, struct ftrace_ret_stack *ret_stack)
     464                 :            : {
     465                 :            :         atomic_set(&t->tracing_graph_pause, 0);
     466                 :            :         atomic_set(&t->trace_overrun, 0);
     467                 :          0 :         t->ftrace_timestamp = 0;
     468                 :            :         /* make curr_ret_stack visible before we add the ret_stack */
     469                 :          0 :         smp_wmb();
     470                 :          0 :         t->ret_stack = ret_stack;
     471                 :            : }
     472                 :            : 
     473                 :            : /*
     474                 :            :  * Allocate a return stack for the idle task. May be the first
     475                 :            :  * time through, or it may be done by CPU hotplug online.
     476                 :            :  */
     477                 :          3 : void ftrace_graph_init_idle_task(struct task_struct *t, int cpu)
     478                 :            : {
     479                 :          3 :         t->curr_ret_stack = -1;
     480                 :          3 :         t->curr_ret_depth = -1;
     481                 :            :         /*
     482                 :            :          * The idle task has no parent, it either has its own
     483                 :            :          * stack or no stack at all.
     484                 :            :          */
     485                 :          3 :         if (t->ret_stack)
     486                 :          0 :                 WARN_ON(t->ret_stack != per_cpu(idle_ret_stack, cpu));
     487                 :            : 
     488                 :          3 :         if (ftrace_graph_active) {
     489                 :            :                 struct ftrace_ret_stack *ret_stack;
     490                 :            : 
     491                 :          0 :                 ret_stack = per_cpu(idle_ret_stack, cpu);
     492                 :          0 :                 if (!ret_stack) {
     493                 :          0 :                         ret_stack =
     494                 :            :                                 kmalloc_array(FTRACE_RETFUNC_DEPTH,
     495                 :            :                                               sizeof(struct ftrace_ret_stack),
     496                 :            :                                               GFP_KERNEL);
     497                 :          0 :                         if (!ret_stack)
     498                 :          3 :                                 return;
     499                 :          0 :                         per_cpu(idle_ret_stack, cpu) = ret_stack;
     500                 :            :                 }
     501                 :            :                 graph_init_task(t, ret_stack);
     502                 :            :         }
     503                 :            : }
     504                 :            : 
     505                 :            : /* Allocate a return stack for newly created task */
     506                 :          3 : void ftrace_graph_init_task(struct task_struct *t)
     507                 :            : {
     508                 :            :         /* Make sure we do not use the parent ret_stack */
     509                 :          3 :         t->ret_stack = NULL;
     510                 :          3 :         t->curr_ret_stack = -1;
     511                 :          3 :         t->curr_ret_depth = -1;
     512                 :            : 
     513                 :          3 :         if (ftrace_graph_active) {
     514                 :            :                 struct ftrace_ret_stack *ret_stack;
     515                 :            : 
     516                 :          0 :                 ret_stack = kmalloc_array(FTRACE_RETFUNC_DEPTH,
     517                 :            :                                           sizeof(struct ftrace_ret_stack),
     518                 :            :                                           GFP_KERNEL);
     519                 :          0 :                 if (!ret_stack)
     520                 :          3 :                         return;
     521                 :            :                 graph_init_task(t, ret_stack);
     522                 :            :         }
     523                 :            : }
     524                 :            : 
     525                 :          3 : void ftrace_graph_exit_task(struct task_struct *t)
     526                 :            : {
     527                 :          3 :         struct ftrace_ret_stack *ret_stack = t->ret_stack;
     528                 :            : 
     529                 :          3 :         t->ret_stack = NULL;
     530                 :            :         /* NULL must become visible to IRQs before we free it: */
     531                 :          3 :         barrier();
     532                 :            : 
     533                 :          3 :         kfree(ret_stack);
     534                 :          3 : }
     535                 :            : 
     536                 :            : /* Allocate a return stack for each task */
     537                 :          0 : static int start_graph_tracing(void)
     538                 :            : {
     539                 :            :         struct ftrace_ret_stack **ret_stack_list;
     540                 :            :         int ret, cpu;
     541                 :            : 
     542                 :          0 :         ret_stack_list = kmalloc_array(FTRACE_RETSTACK_ALLOC_SIZE,
     543                 :            :                                        sizeof(struct ftrace_ret_stack *),
     544                 :            :                                        GFP_KERNEL);
     545                 :            : 
     546                 :          0 :         if (!ret_stack_list)
     547                 :            :                 return -ENOMEM;
     548                 :            : 
     549                 :            :         /* The cpu_boot init_task->ret_stack will never be freed */
     550                 :          0 :         for_each_online_cpu(cpu) {
     551                 :          0 :                 if (!idle_task(cpu)->ret_stack)
     552                 :          0 :                         ftrace_graph_init_idle_task(idle_task(cpu), cpu);
     553                 :            :         }
     554                 :            : 
     555                 :            :         do {
     556                 :          0 :                 ret = alloc_retstack_tasklist(ret_stack_list);
     557                 :          0 :         } while (ret == -EAGAIN);
     558                 :            : 
     559                 :          0 :         if (!ret) {
     560                 :            :                 ret = register_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
     561                 :          0 :                 if (ret)
     562                 :          0 :                         pr_info("ftrace_graph: Couldn't activate tracepoint"
     563                 :            :                                 " probe to kernel_sched_switch\n");
     564                 :            :         }
     565                 :            : 
     566                 :          0 :         kfree(ret_stack_list);
     567                 :          0 :         return ret;
     568                 :            : }
     569                 :            : 
     570                 :          0 : int register_ftrace_graph(struct fgraph_ops *gops)
     571                 :            : {
     572                 :            :         int ret = 0;
     573                 :            : 
     574                 :          0 :         mutex_lock(&ftrace_lock);
     575                 :            : 
     576                 :            :         /* we currently allow only one tracer registered at a time */
     577                 :          0 :         if (ftrace_graph_active) {
     578                 :            :                 ret = -EBUSY;
     579                 :            :                 goto out;
     580                 :            :         }
     581                 :            : 
     582                 :            :         register_pm_notifier(&ftrace_suspend_notifier);
     583                 :            : 
     584                 :          0 :         ftrace_graph_active++;
     585                 :          0 :         ret = start_graph_tracing();
     586                 :          0 :         if (ret) {
     587                 :          0 :                 ftrace_graph_active--;
     588                 :          0 :                 goto out;
     589                 :            :         }
     590                 :            : 
     591                 :          0 :         ftrace_graph_return = gops->retfunc;
     592                 :            : 
     593                 :            :         /*
     594                 :            :          * Update the indirect function to the entryfunc, and the
     595                 :            :          * function that gets called to the entry_test first. Then
     596                 :            :          * call the update fgraph entry function to determine if
     597                 :            :          * the entryfunc should be called directly or not.
     598                 :            :          */
     599                 :          0 :         __ftrace_graph_entry = gops->entryfunc;
     600                 :          0 :         ftrace_graph_entry = ftrace_graph_entry_test;
     601                 :          0 :         update_function_graph_func();
     602                 :            : 
     603                 :          0 :         ret = ftrace_startup(&graph_ops, FTRACE_START_FUNC_RET);
     604                 :            : out:
     605                 :          0 :         mutex_unlock(&ftrace_lock);
     606                 :          0 :         return ret;
     607                 :            : }
     608                 :            : 
     609                 :          0 : void unregister_ftrace_graph(struct fgraph_ops *gops)
     610                 :            : {
     611                 :          0 :         mutex_lock(&ftrace_lock);
     612                 :            : 
     613                 :          0 :         if (unlikely(!ftrace_graph_active))
     614                 :            :                 goto out;
     615                 :            : 
     616                 :          0 :         ftrace_graph_active--;
     617                 :          0 :         ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub;
     618                 :          0 :         ftrace_graph_entry = ftrace_graph_entry_stub;
     619                 :          0 :         __ftrace_graph_entry = ftrace_graph_entry_stub;
     620                 :          0 :         ftrace_shutdown(&graph_ops, FTRACE_STOP_FUNC_RET);
     621                 :            :         unregister_pm_notifier(&ftrace_suspend_notifier);
     622                 :            :         unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
     623                 :            : 
     624                 :            :  out:
     625                 :          0 :         mutex_unlock(&ftrace_lock);
     626                 :          0 : }
    

Generated by: LCOV version 1.14