···29293030typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip);31313232+struct ftrace_hash;3333+3434+enum {3535+ FTRACE_OPS_FL_ENABLED = 1 << 0,3636+ FTRACE_OPS_FL_GLOBAL = 1 << 1,3737+ FTRACE_OPS_FL_DYNAMIC = 1 << 2,3838+};3939+3240struct ftrace_ops {3333- ftrace_func_t func;3434- struct ftrace_ops *next;4141+ ftrace_func_t func;4242+ struct ftrace_ops *next;4343+ unsigned long flags;4444+#ifdef CONFIG_DYNAMIC_FTRACE4545+ struct ftrace_hash *notrace_hash;4646+ struct ftrace_hash *filter_hash;4747+#endif3548};36493750extern int function_trace_stop;···159146extern int ftrace_text_reserved(void *start, void *end);160147161148enum {162162- FTRACE_FL_FREE = (1 << 0),163163- FTRACE_FL_FILTER = (1 << 1),164164- FTRACE_FL_ENABLED = (1 << 2),165165- FTRACE_FL_NOTRACE = (1 << 3),149149+ FTRACE_FL_ENABLED = (1 << 30),150150+ FTRACE_FL_FREE = (1 << 31),166151};152152+153153+#define FTRACE_FL_MASK (0x3UL << 30)154154+#define FTRACE_REF_MAX ((1 << 30) - 1)167155168156struct dyn_ftrace {169157 union {···179165};180166181167int ftrace_force_update(void);182182-void ftrace_set_filter(unsigned char *buf, int len, int reset);168168+void ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,169169+ int len, int reset);170170+void ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,171171+ int len, int reset);172172+void ftrace_set_global_filter(unsigned char *buf, int len, int reset);173173+void ftrace_set_global_notrace(unsigned char *buf, int len, int reset);183174184175int register_ftrace_command(struct ftrace_func_command *cmd);185176int unregister_ftrace_command(struct ftrace_func_command *cmd);
+1
include/linux/kernel.h
···283283extern unsigned long long memparse(const char *ptr, char **retptr);284284285285extern int core_kernel_text(unsigned long addr);286286+extern int core_kernel_data(unsigned long addr);286287extern int __kernel_text_address(unsigned long addr);287288extern int kernel_text_address(unsigned long addr);288289extern int func_ptr_is_kernel_text(void *ptr);
+8
kernel/extable.c
···7272 return 0;7373}74747575+int core_kernel_data(unsigned long addr)7676+{7777+ if (addr >= (unsigned long)_sdata &&7878+ addr < (unsigned long)_edata)7979+ return 1;8080+ return 0;8181+}8282+7583int __kernel_text_address(unsigned long addr)7684{7785 if (core_kernel_text(addr))
+863-141
kernel/trace/ftrace.c
···5757/* hash bits for specific function selection */5858#define FTRACE_HASH_BITS 75959#define FTRACE_FUNC_HASHSIZE (1 << FTRACE_HASH_BITS)6060+#define FTRACE_HASH_DEFAULT_BITS 106161+#define FTRACE_HASH_MAX_BITS 1260626163/* ftrace_enabled is a method to turn ftrace on or off */6264int ftrace_enabled __read_mostly;···8785 .func = ftrace_stub,8886};89879090-static struct ftrace_ops *ftrace_list __read_mostly = &ftrace_list_end;8888+static struct ftrace_ops *ftrace_global_list __read_mostly = &ftrace_list_end;8989+static struct ftrace_ops *ftrace_ops_list __read_mostly = &ftrace_list_end;9190ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub;9291ftrace_func_t __ftrace_trace_function __read_mostly = ftrace_stub;9392ftrace_func_t ftrace_pid_function __read_mostly = ftrace_stub;9393+static struct ftrace_ops global_ops;9494+9595+static void9696+ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip);94979598/*9696- * Traverse the ftrace_list, invoking all entries. The reason that we9999+ * Traverse the ftrace_global_list, invoking all entries. The reason that we97100 * can use rcu_dereference_raw() is that elements removed from this list98101 * are simply leaked, so there is no need to interact with a grace-period99102 * mechanism. The rcu_dereference_raw() calls are needed to handle100100- * concurrent insertions into the ftrace_list.103103+ * concurrent insertions into the ftrace_global_list.101104 *102105 * Silly Alpha and silly pointer-speculation compiler optimizations!103106 */104104-static void ftrace_list_func(unsigned long ip, unsigned long parent_ip)107107+static void ftrace_global_list_func(unsigned long ip,108108+ unsigned long parent_ip)105109{106106- struct ftrace_ops *op = rcu_dereference_raw(ftrace_list); /*see above*/110110+ struct ftrace_ops *op = rcu_dereference_raw(ftrace_global_list); /*see above*/107111108112 while (op != &ftrace_list_end) {109113 op->func(ip, parent_ip);···159151}160152#endif161153162162-static void update_ftrace_function(void)154154+static void update_global_ops(void)163155{164156 ftrace_func_t func;165157···168160 * function directly. Otherwise, we need to iterate over the169161 * registered callers.170162 */171171- if (ftrace_list == &ftrace_list_end ||172172- ftrace_list->next == &ftrace_list_end)173173- func = ftrace_list->func;163163+ if (ftrace_global_list == &ftrace_list_end ||164164+ ftrace_global_list->next == &ftrace_list_end)165165+ func = ftrace_global_list->func;174166 else175175- func = ftrace_list_func;167167+ func = ftrace_global_list_func;176168177169 /* If we filter on pids, update to use the pid function */178170 if (!list_empty(&ftrace_pids)) {179171 set_ftrace_pid_function(func);180172 func = ftrace_pid_func;181173 }174174+175175+ global_ops.func = func;176176+}177177+178178+static void update_ftrace_function(void)179179+{180180+ ftrace_func_t func;181181+182182+ update_global_ops();183183+184184+ /*185185+ * If we are at the end of the list and this ops is186186+ * not dynamic, then have the mcount trampoline call187187+ * the function directly188188+ */189189+ if (ftrace_ops_list == &ftrace_list_end ||190190+ (ftrace_ops_list->next == &ftrace_list_end &&191191+ !(ftrace_ops_list->flags & FTRACE_OPS_FL_DYNAMIC)))192192+ func = ftrace_ops_list->func;193193+ else194194+ func = ftrace_ops_list_func;195195+182196#ifdef CONFIG_HAVE_FUNCTION_TRACE_MCOUNT_TEST183197 ftrace_trace_function = func;184198#else···209179#endif210180}211181212212-static int __register_ftrace_function(struct ftrace_ops *ops)182182+static void add_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops)213183{214214- ops->next = ftrace_list;184184+ ops->next = *list;215185 /*216216- * We are entering ops into the ftrace_list but another186186+ * We are entering ops into the list but another217187 * CPU might be walking that list. We need to make sure218188 * the ops->next pointer is valid before another CPU sees219219- * the ops pointer included into the ftrace_list.189189+ * the ops pointer included into the list.220190 */221221- rcu_assign_pointer(ftrace_list, ops);191191+ rcu_assign_pointer(*list, ops);192192+}193193+194194+static int remove_ftrace_ops(struct ftrace_ops **list, struct ftrace_ops *ops)195195+{196196+ struct ftrace_ops **p;197197+198198+ /*199199+ * If we are removing the last function, then simply point200200+ * to the ftrace_stub.201201+ */202202+ if (*list == ops && ops->next == &ftrace_list_end) {203203+ *list = &ftrace_list_end;204204+ return 0;205205+ }206206+207207+ for (p = list; *p != &ftrace_list_end; p = &(*p)->next)208208+ if (*p == ops)209209+ break;210210+211211+ if (*p != ops)212212+ return -1;213213+214214+ *p = (*p)->next;215215+ return 0;216216+}217217+218218+static int __register_ftrace_function(struct ftrace_ops *ops)219219+{220220+ if (ftrace_disabled)221221+ return -ENODEV;222222+223223+ if (FTRACE_WARN_ON(ops == &global_ops))224224+ return -EINVAL;225225+226226+ if (WARN_ON(ops->flags & FTRACE_OPS_FL_ENABLED))227227+ return -EBUSY;228228+229229+ if (!core_kernel_data((unsigned long)ops))230230+ ops->flags |= FTRACE_OPS_FL_DYNAMIC;231231+232232+ if (ops->flags & FTRACE_OPS_FL_GLOBAL) {233233+ int first = ftrace_global_list == &ftrace_list_end;234234+ add_ftrace_ops(&ftrace_global_list, ops);235235+ ops->flags |= FTRACE_OPS_FL_ENABLED;236236+ if (first)237237+ add_ftrace_ops(&ftrace_ops_list, &global_ops);238238+ } else239239+ add_ftrace_ops(&ftrace_ops_list, ops);222240223241 if (ftrace_enabled)224242 update_ftrace_function();···276198277199static int __unregister_ftrace_function(struct ftrace_ops *ops)278200{279279- struct ftrace_ops **p;201201+ int ret;280202281281- /*282282- * If we are removing the last function, then simply point283283- * to the ftrace_stub.284284- */285285- if (ftrace_list == ops && ops->next == &ftrace_list_end) {286286- ftrace_trace_function = ftrace_stub;287287- ftrace_list = &ftrace_list_end;288288- return 0;289289- }203203+ if (ftrace_disabled)204204+ return -ENODEV;290205291291- for (p = &ftrace_list; *p != &ftrace_list_end; p = &(*p)->next)292292- if (*p == ops)293293- break;206206+ if (WARN_ON(!(ops->flags & FTRACE_OPS_FL_ENABLED)))207207+ return -EBUSY;294208295295- if (*p != ops)296296- return -1;209209+ if (FTRACE_WARN_ON(ops == &global_ops))210210+ return -EINVAL;297211298298- *p = (*p)->next;212212+ if (ops->flags & FTRACE_OPS_FL_GLOBAL) {213213+ ret = remove_ftrace_ops(&ftrace_global_list, ops);214214+ if (!ret && ftrace_global_list == &ftrace_list_end)215215+ ret = remove_ftrace_ops(&ftrace_ops_list, &global_ops);216216+ if (!ret)217217+ ops->flags &= ~FTRACE_OPS_FL_ENABLED;218218+ } else219219+ ret = remove_ftrace_ops(&ftrace_ops_list, ops);220220+221221+ if (ret < 0)222222+ return ret;299223300224 if (ftrace_enabled)301225 update_ftrace_function();226226+227227+ /*228228+ * Dynamic ops may be freed, we must make sure that all229229+ * callers are done before leaving this function.230230+ */231231+ if (ops->flags & FTRACE_OPS_FL_DYNAMIC)232232+ synchronize_sched();302233303234 return 0;304235}···952865 FTRACE_START_FUNC_RET = (1 << 3),953866 FTRACE_STOP_FUNC_RET = (1 << 4),954867};868868+struct ftrace_func_entry {869869+ struct hlist_node hlist;870870+ unsigned long ip;871871+};955872956956-static int ftrace_filtered;873873+struct ftrace_hash {874874+ unsigned long size_bits;875875+ struct hlist_head *buckets;876876+ unsigned long count;877877+ struct rcu_head rcu;878878+};879879+880880+/*881881+ * We make these constant because no one should touch them,882882+ * but they are used as the default "empty hash", to avoid allocating883883+ * it all the time. These are in a read only section such that if884884+ * anyone does try to modify it, it will cause an exception.885885+ */886886+static const struct hlist_head empty_buckets[1];887887+static const struct ftrace_hash empty_hash = {888888+ .buckets = (struct hlist_head *)empty_buckets,889889+};890890+#define EMPTY_HASH ((struct ftrace_hash *)&empty_hash)891891+892892+static struct ftrace_ops global_ops = {893893+ .func = ftrace_stub,894894+ .notrace_hash = EMPTY_HASH,895895+ .filter_hash = EMPTY_HASH,896896+};957897958898static struct dyn_ftrace *ftrace_new_addrs;959899···10038891004890static struct dyn_ftrace *ftrace_free_records;1005891892892+static struct ftrace_func_entry *893893+ftrace_lookup_ip(struct ftrace_hash *hash, unsigned long ip)894894+{895895+ unsigned long key;896896+ struct ftrace_func_entry *entry;897897+ struct hlist_head *hhd;898898+ struct hlist_node *n;899899+900900+ if (!hash->count)901901+ return NULL;902902+903903+ if (hash->size_bits > 0)904904+ key = hash_long(ip, hash->size_bits);905905+ else906906+ key = 0;907907+908908+ hhd = &hash->buckets[key];909909+910910+ hlist_for_each_entry_rcu(entry, n, hhd, hlist) {911911+ if (entry->ip == ip)912912+ return entry;913913+ }914914+ return NULL;915915+}916916+917917+static void __add_hash_entry(struct ftrace_hash *hash,918918+ struct ftrace_func_entry *entry)919919+{920920+ struct hlist_head *hhd;921921+ unsigned long key;922922+923923+ if (hash->size_bits)924924+ key = hash_long(entry->ip, hash->size_bits);925925+ else926926+ key = 0;927927+928928+ hhd = &hash->buckets[key];929929+ hlist_add_head(&entry->hlist, hhd);930930+ hash->count++;931931+}932932+933933+static int add_hash_entry(struct ftrace_hash *hash, unsigned long ip)934934+{935935+ struct ftrace_func_entry *entry;936936+937937+ entry = kmalloc(sizeof(*entry), GFP_KERNEL);938938+ if (!entry)939939+ return -ENOMEM;940940+941941+ entry->ip = ip;942942+ __add_hash_entry(hash, entry);943943+944944+ return 0;945945+}946946+947947+static void948948+free_hash_entry(struct ftrace_hash *hash,949949+ struct ftrace_func_entry *entry)950950+{951951+ hlist_del(&entry->hlist);952952+ kfree(entry);953953+ hash->count--;954954+}955955+956956+static void957957+remove_hash_entry(struct ftrace_hash *hash,958958+ struct ftrace_func_entry *entry)959959+{960960+ hlist_del(&entry->hlist);961961+ hash->count--;962962+}963963+964964+static void ftrace_hash_clear(struct ftrace_hash *hash)965965+{966966+ struct hlist_head *hhd;967967+ struct hlist_node *tp, *tn;968968+ struct ftrace_func_entry *entry;969969+ int size = 1 << hash->size_bits;970970+ int i;971971+972972+ if (!hash->count)973973+ return;974974+975975+ for (i = 0; i < size; i++) {976976+ hhd = &hash->buckets[i];977977+ hlist_for_each_entry_safe(entry, tp, tn, hhd, hlist)978978+ free_hash_entry(hash, entry);979979+ }980980+ FTRACE_WARN_ON(hash->count);981981+}982982+983983+static void free_ftrace_hash(struct ftrace_hash *hash)984984+{985985+ if (!hash || hash == EMPTY_HASH)986986+ return;987987+ ftrace_hash_clear(hash);988988+ kfree(hash->buckets);989989+ kfree(hash);990990+}991991+992992+static void __free_ftrace_hash_rcu(struct rcu_head *rcu)993993+{994994+ struct ftrace_hash *hash;995995+996996+ hash = container_of(rcu, struct ftrace_hash, rcu);997997+ free_ftrace_hash(hash);998998+}999999+10001000+static void free_ftrace_hash_rcu(struct ftrace_hash *hash)10011001+{10021002+ if (!hash || hash == EMPTY_HASH)10031003+ return;10041004+ call_rcu_sched(&hash->rcu, __free_ftrace_hash_rcu);10051005+}10061006+10071007+static struct ftrace_hash *alloc_ftrace_hash(int size_bits)10081008+{10091009+ struct ftrace_hash *hash;10101010+ int size;10111011+10121012+ hash = kzalloc(sizeof(*hash), GFP_KERNEL);10131013+ if (!hash)10141014+ return NULL;10151015+10161016+ size = 1 << size_bits;10171017+ hash->buckets = kzalloc(sizeof(*hash->buckets) * size, GFP_KERNEL);10181018+10191019+ if (!hash->buckets) {10201020+ kfree(hash);10211021+ return NULL;10221022+ }10231023+10241024+ hash->size_bits = size_bits;10251025+10261026+ return hash;10271027+}10281028+10291029+static struct ftrace_hash *10301030+alloc_and_copy_ftrace_hash(int size_bits, struct ftrace_hash *hash)10311031+{10321032+ struct ftrace_func_entry *entry;10331033+ struct ftrace_hash *new_hash;10341034+ struct hlist_node *tp;10351035+ int size;10361036+ int ret;10371037+ int i;10381038+10391039+ new_hash = alloc_ftrace_hash(size_bits);10401040+ if (!new_hash)10411041+ return NULL;10421042+10431043+ /* Empty hash? */10441044+ if (!hash || !hash->count)10451045+ return new_hash;10461046+10471047+ size = 1 << hash->size_bits;10481048+ for (i = 0; i < size; i++) {10491049+ hlist_for_each_entry(entry, tp, &hash->buckets[i], hlist) {10501050+ ret = add_hash_entry(new_hash, entry->ip);10511051+ if (ret < 0)10521052+ goto free_hash;10531053+ }10541054+ }10551055+10561056+ FTRACE_WARN_ON(new_hash->count != hash->count);10571057+10581058+ return new_hash;10591059+10601060+ free_hash:10611061+ free_ftrace_hash(new_hash);10621062+ return NULL;10631063+}10641064+10651065+static int10661066+ftrace_hash_move(struct ftrace_hash **dst, struct ftrace_hash *src)10671067+{10681068+ struct ftrace_func_entry *entry;10691069+ struct hlist_node *tp, *tn;10701070+ struct hlist_head *hhd;10711071+ struct ftrace_hash *old_hash;10721072+ struct ftrace_hash *new_hash;10731073+ unsigned long key;10741074+ int size = src->count;10751075+ int bits = 0;10761076+ int i;10771077+10781078+ /*10791079+ * If the new source is empty, just free dst and assign it10801080+ * the empty_hash.10811081+ */10821082+ if (!src->count) {10831083+ free_ftrace_hash_rcu(*dst);10841084+ rcu_assign_pointer(*dst, EMPTY_HASH);10851085+ return 0;10861086+ }10871087+10881088+ /*10891089+ * Make the hash size about 1/2 the # found10901090+ */10911091+ for (size /= 2; size; size >>= 1)10921092+ bits++;10931093+10941094+ /* Don't allocate too much */10951095+ if (bits > FTRACE_HASH_MAX_BITS)10961096+ bits = FTRACE_HASH_MAX_BITS;10971097+10981098+ new_hash = alloc_ftrace_hash(bits);10991099+ if (!new_hash)11001100+ return -ENOMEM;11011101+11021102+ size = 1 << src->size_bits;11031103+ for (i = 0; i < size; i++) {11041104+ hhd = &src->buckets[i];11051105+ hlist_for_each_entry_safe(entry, tp, tn, hhd, hlist) {11061106+ if (bits > 0)11071107+ key = hash_long(entry->ip, bits);11081108+ else11091109+ key = 0;11101110+ remove_hash_entry(src, entry);11111111+ __add_hash_entry(new_hash, entry);11121112+ }11131113+ }11141114+11151115+ old_hash = *dst;11161116+ rcu_assign_pointer(*dst, new_hash);11171117+ free_ftrace_hash_rcu(old_hash);11181118+11191119+ return 0;11201120+}11211121+11221122+/*11231123+ * Test the hashes for this ops to see if we want to call11241124+ * the ops->func or not.11251125+ *11261126+ * It's a match if the ip is in the ops->filter_hash or11271127+ * the filter_hash does not exist or is empty,11281128+ * AND11291129+ * the ip is not in the ops->notrace_hash.11301130+ *11311131+ * This needs to be called with preemption disabled as11321132+ * the hashes are freed with call_rcu_sched().11331133+ */11341134+static int11351135+ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)11361136+{11371137+ struct ftrace_hash *filter_hash;11381138+ struct ftrace_hash *notrace_hash;11391139+ int ret;11401140+11411141+ filter_hash = rcu_dereference_raw(ops->filter_hash);11421142+ notrace_hash = rcu_dereference_raw(ops->notrace_hash);11431143+11441144+ if ((!filter_hash || !filter_hash->count ||11451145+ ftrace_lookup_ip(filter_hash, ip)) &&11461146+ (!notrace_hash || !notrace_hash->count ||11471147+ !ftrace_lookup_ip(notrace_hash, ip)))11481148+ ret = 1;11491149+ else11501150+ ret = 0;11511151+11521152+ return ret;11531153+}11541154+10061155/*10071156 * This is a double for. Do not use 'break' to break out of the loop,10081157 * you must use a goto.···1279902#define while_for_each_ftrace_rec() \1280903 } \1281904 }905905+906906+static void __ftrace_hash_rec_update(struct ftrace_ops *ops,907907+ int filter_hash,908908+ bool inc)909909+{910910+ struct ftrace_hash *hash;911911+ struct ftrace_hash *other_hash;912912+ struct ftrace_page *pg;913913+ struct dyn_ftrace *rec;914914+ int count = 0;915915+ int all = 0;916916+917917+ /* Only update if the ops has been registered */918918+ if (!(ops->flags & FTRACE_OPS_FL_ENABLED))919919+ return;920920+921921+ /*922922+ * In the filter_hash case:923923+ * If the count is zero, we update all records.924924+ * Otherwise we just update the items in the hash.925925+ *926926+ * In the notrace_hash case:927927+ * We enable the update in the hash.928928+ * As disabling notrace means enabling the tracing,929929+ * and enabling notrace means disabling, the inc variable930930+ * gets inversed.931931+ */932932+ if (filter_hash) {933933+ hash = ops->filter_hash;934934+ other_hash = ops->notrace_hash;935935+ if (!hash || !hash->count)936936+ all = 1;937937+ } else {938938+ inc = !inc;939939+ hash = ops->notrace_hash;940940+ other_hash = ops->filter_hash;941941+ /*942942+ * If the notrace hash has no items,943943+ * then there's nothing to do.944944+ */945945+ if (hash && !hash->count)946946+ return;947947+ }948948+949949+ do_for_each_ftrace_rec(pg, rec) {950950+ int in_other_hash = 0;951951+ int in_hash = 0;952952+ int match = 0;953953+954954+ if (all) {955955+ /*956956+ * Only the filter_hash affects all records.957957+ * Update if the record is not in the notrace hash.958958+ */959959+ if (!other_hash || !ftrace_lookup_ip(other_hash, rec->ip))960960+ match = 1;961961+ } else {962962+ in_hash = hash && !!ftrace_lookup_ip(hash, rec->ip);963963+ in_other_hash = other_hash && !!ftrace_lookup_ip(other_hash, rec->ip);964964+965965+ /*966966+ *967967+ */968968+ if (filter_hash && in_hash && !in_other_hash)969969+ match = 1;970970+ else if (!filter_hash && in_hash &&971971+ (in_other_hash || !other_hash->count))972972+ match = 1;973973+ }974974+ if (!match)975975+ continue;976976+977977+ if (inc) {978978+ rec->flags++;979979+ if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == FTRACE_REF_MAX))980980+ return;981981+ } else {982982+ if (FTRACE_WARN_ON((rec->flags & ~FTRACE_FL_MASK) == 0))983983+ return;984984+ rec->flags--;985985+ }986986+ count++;987987+ /* Shortcut, if we handled all records, we are done. */988988+ if (!all && count == hash->count)989989+ return;990990+ } while_for_each_ftrace_rec();991991+}992992+993993+static void ftrace_hash_rec_disable(struct ftrace_ops *ops,994994+ int filter_hash)995995+{996996+ __ftrace_hash_rec_update(ops, filter_hash, 0);997997+}998998+999999+static void ftrace_hash_rec_enable(struct ftrace_ops *ops,10001000+ int filter_hash)10011001+{10021002+ __ftrace_hash_rec_update(ops, filter_hash, 1);10031003+}1282100412831005static void ftrace_free_rec(struct dyn_ftrace *rec)12841006{···15001024 ftrace_addr = (unsigned long)FTRACE_ADDR;1501102515021026 /*15031503- * If this record is not to be traced or we want to disable it,15041504- * then disable it.10271027+ * If we are enabling tracing:15051028 *15061506- * If we want to enable it and filtering is off, then enable it.10291029+ * If the record has a ref count, then we need to enable it10301030+ * because someone is using it.15071031 *15081508- * If we want to enable it and filtering is on, enable it only if15091509- * it's filtered10321032+ * Otherwise we make sure its disabled.10331033+ *10341034+ * If we are disabling tracing, then disable all records that10351035+ * are enabled.15101036 */15111511- if (enable && !(rec->flags & FTRACE_FL_NOTRACE)) {15121512- if (!ftrace_filtered || (rec->flags & FTRACE_FL_FILTER))15131513- flag = FTRACE_FL_ENABLED;15141514- }10371037+ if (enable && (rec->flags & ~FTRACE_FL_MASK))10381038+ flag = FTRACE_FL_ENABLED;1515103915161040 /* If the state of this record hasn't changed, then do nothing */15171041 if ((rec->flags & FTRACE_FL_ENABLED) == flag)···1623114716241148static ftrace_func_t saved_ftrace_func;16251149static int ftrace_start_up;11501150+static int global_start_up;1626115116271152static void ftrace_startup_enable(int command)16281153{···16381161 ftrace_run_update_code(command);16391162}1640116316411641-static void ftrace_startup(int command)11641164+static void ftrace_startup(struct ftrace_ops *ops, int command)16421165{11661166+ bool hash_enable = true;11671167+16431168 if (unlikely(ftrace_disabled))16441169 return;1645117016461171 ftrace_start_up++;16471172 command |= FTRACE_ENABLE_CALLS;1648117311741174+ /* ops marked global share the filter hashes */11751175+ if (ops->flags & FTRACE_OPS_FL_GLOBAL) {11761176+ ops = &global_ops;11771177+ /* Don't update hash if global is already set */11781178+ if (global_start_up)11791179+ hash_enable = false;11801180+ global_start_up++;11811181+ }11821182+11831183+ ops->flags |= FTRACE_OPS_FL_ENABLED;11841184+ if (hash_enable)11851185+ ftrace_hash_rec_enable(ops, 1);11861186+16491187 ftrace_startup_enable(command);16501188}1651118916521652-static void ftrace_shutdown(int command)11901190+static void ftrace_shutdown(struct ftrace_ops *ops, int command)16531191{11921192+ bool hash_disable = true;11931193+16541194 if (unlikely(ftrace_disabled))16551195 return;16561196···16781184 * further ftrace uses.16791185 */16801186 WARN_ON_ONCE(ftrace_start_up < 0);11871187+11881188+ if (ops->flags & FTRACE_OPS_FL_GLOBAL) {11891189+ ops = &global_ops;11901190+ global_start_up--;11911191+ WARN_ON_ONCE(global_start_up < 0);11921192+ /* Don't update hash if global still has users */11931193+ if (global_start_up) {11941194+ WARN_ON_ONCE(!ftrace_start_up);11951195+ hash_disable = false;11961196+ }11971197+ }11981198+11991199+ if (hash_disable)12001200+ ftrace_hash_rec_disable(ops, 1);12011201+12021202+ if (ops != &global_ops || !global_start_up)12031203+ ops->flags &= ~FTRACE_OPS_FL_ENABLED;1681120416821205 if (!ftrace_start_up)16831206 command |= FTRACE_DISABLE_CALLS;···18401329 FTRACE_ITER_NOTRACE = (1 << 1),18411330 FTRACE_ITER_PRINTALL = (1 << 2),18421331 FTRACE_ITER_HASH = (1 << 3),13321332+ FTRACE_ITER_ENABLED = (1 << 4),18431333};1844133418451335#define FTRACE_BUFF_MAX (KSYM_SYMBOL_LEN+4) /* room for wildcards */···18521340 struct dyn_ftrace *func;18531341 struct ftrace_func_probe *probe;18541342 struct trace_parser parser;13431343+ struct ftrace_hash *hash;13441344+ struct ftrace_ops *ops;18551345 int hidx;18561346 int idx;18571347 unsigned flags;···19501436t_next(struct seq_file *m, void *v, loff_t *pos)19511437{19521438 struct ftrace_iterator *iter = m->private;14391439+ struct ftrace_ops *ops = &global_ops;19531440 struct dyn_ftrace *rec = NULL;1954144119551442 if (unlikely(ftrace_disabled))···19771462 if ((rec->flags & FTRACE_FL_FREE) ||1978146319791464 ((iter->flags & FTRACE_ITER_FILTER) &&19801980- !(rec->flags & FTRACE_FL_FILTER)) ||14651465+ !(ftrace_lookup_ip(ops->filter_hash, rec->ip))) ||1981146619821467 ((iter->flags & FTRACE_ITER_NOTRACE) &&19831983- !(rec->flags & FTRACE_FL_NOTRACE))) {14681468+ !ftrace_lookup_ip(ops->notrace_hash, rec->ip)) ||14691469+14701470+ ((iter->flags & FTRACE_ITER_ENABLED) &&14711471+ !(rec->flags & ~FTRACE_FL_MASK))) {14721472+19841473 rec = NULL;19851474 goto retry;19861475 }···20081489static void *t_start(struct seq_file *m, loff_t *pos)20091490{20101491 struct ftrace_iterator *iter = m->private;14921492+ struct ftrace_ops *ops = &global_ops;20111493 void *p = NULL;20121494 loff_t l;20131495···20281508 * off, we can short cut and just print out that all20291509 * functions are enabled.20301510 */20312031- if (iter->flags & FTRACE_ITER_FILTER && !ftrace_filtered) {15111511+ if (iter->flags & FTRACE_ITER_FILTER && !ops->filter_hash->count) {20321512 if (*pos > 0)20331513 return t_hash_start(m, pos);20341514 iter->flags |= FTRACE_ITER_PRINTALL;···20861566 if (!rec)20871567 return 0;2088156820892089- seq_printf(m, "%ps\n", (void *)rec->ip);15691569+ seq_printf(m, "%ps", (void *)rec->ip);15701570+ if (iter->flags & FTRACE_ITER_ENABLED)15711571+ seq_printf(m, " (%ld)",15721572+ rec->flags & ~FTRACE_FL_MASK);15731573+ seq_printf(m, "\n");2090157420911575 return 0;20921576}···21291605 return ret;21301606}2131160721322132-static void ftrace_filter_reset(int enable)16081608+static int16091609+ftrace_enabled_open(struct inode *inode, struct file *file)21331610{21342134- struct ftrace_page *pg;21352135- struct dyn_ftrace *rec;21362136- unsigned long type = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;16111611+ struct ftrace_iterator *iter;16121612+ int ret;2137161316141614+ if (unlikely(ftrace_disabled))16151615+ return -ENODEV;16161616+16171617+ iter = kzalloc(sizeof(*iter), GFP_KERNEL);16181618+ if (!iter)16191619+ return -ENOMEM;16201620+16211621+ iter->pg = ftrace_pages_start;16221622+ iter->flags = FTRACE_ITER_ENABLED;16231623+16241624+ ret = seq_open(file, &show_ftrace_seq_ops);16251625+ if (!ret) {16261626+ struct seq_file *m = file->private_data;16271627+16281628+ m->private = iter;16291629+ } else {16301630+ kfree(iter);16311631+ }16321632+16331633+ return ret;16341634+}16351635+16361636+static void ftrace_filter_reset(struct ftrace_hash *hash)16371637+{21381638 mutex_lock(&ftrace_lock);21392139- if (enable)21402140- ftrace_filtered = 0;21412141- do_for_each_ftrace_rec(pg, rec) {21422142- rec->flags &= ~type;21432143- } while_for_each_ftrace_rec();16391639+ ftrace_hash_clear(hash);21441640 mutex_unlock(&ftrace_lock);21451641}2146164221471643static int21482148-ftrace_regex_open(struct inode *inode, struct file *file, int enable)16441644+ftrace_regex_open(struct ftrace_ops *ops, int flag,16451645+ struct inode *inode, struct file *file)21491646{21501647 struct ftrace_iterator *iter;16481648+ struct ftrace_hash *hash;21511649 int ret = 0;2152165021531651 if (unlikely(ftrace_disabled))···21841638 return -ENOMEM;21851639 }2186164016411641+ if (flag & FTRACE_ITER_NOTRACE)16421642+ hash = ops->notrace_hash;16431643+ else16441644+ hash = ops->filter_hash;16451645+16461646+ iter->ops = ops;16471647+ iter->flags = flag;16481648+16491649+ if (file->f_mode & FMODE_WRITE) {16501650+ mutex_lock(&ftrace_lock);16511651+ iter->hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, hash);16521652+ mutex_unlock(&ftrace_lock);16531653+16541654+ if (!iter->hash) {16551655+ trace_parser_put(&iter->parser);16561656+ kfree(iter);16571657+ return -ENOMEM;16581658+ }16591659+ }16601660+21871661 mutex_lock(&ftrace_regex_lock);16621662+21881663 if ((file->f_mode & FMODE_WRITE) &&21891664 (file->f_flags & O_TRUNC))21902190- ftrace_filter_reset(enable);16651665+ ftrace_filter_reset(iter->hash);2191166621921667 if (file->f_mode & FMODE_READ) {21931668 iter->pg = ftrace_pages_start;21942194- iter->flags = enable ? FTRACE_ITER_FILTER :21952195- FTRACE_ITER_NOTRACE;2196166921971670 ret = seq_open(file, &show_ftrace_seq_ops);21981671 if (!ret) {21991672 struct seq_file *m = file->private_data;22001673 m->private = iter;22011674 } else {16751675+ /* Failed */16761676+ free_ftrace_hash(iter->hash);22021677 trace_parser_put(&iter->parser);22031678 kfree(iter);22041679 }···22331666static int22341667ftrace_filter_open(struct inode *inode, struct file *file)22351668{22362236- return ftrace_regex_open(inode, file, 1);16691669+ return ftrace_regex_open(&global_ops, FTRACE_ITER_FILTER,16701670+ inode, file);22371671}2238167222391673static int22401674ftrace_notrace_open(struct inode *inode, struct file *file)22411675{22422242- return ftrace_regex_open(inode, file, 0);16761676+ return ftrace_regex_open(&global_ops, FTRACE_ITER_NOTRACE,16771677+ inode, file);22431678}2244167922451680static loff_t···22851716 return matched;22861717}2287171822882288-static void22892289-update_record(struct dyn_ftrace *rec, unsigned long flag, int not)17191719+static int17201720+enter_record(struct ftrace_hash *hash, struct dyn_ftrace *rec, int not)22901721{22912291- if (not)22922292- rec->flags &= ~flag;22932293- else22942294- rec->flags |= flag;17221722+ struct ftrace_func_entry *entry;17231723+ int ret = 0;17241724+17251725+ entry = ftrace_lookup_ip(hash, rec->ip);17261726+ if (not) {17271727+ /* Do nothing if it doesn't exist */17281728+ if (!entry)17291729+ return 0;17301730+17311731+ free_hash_entry(hash, entry);17321732+ } else {17331733+ /* Do nothing if it exists */17341734+ if (entry)17351735+ return 0;17361736+17371737+ ret = add_hash_entry(hash, rec->ip);17381738+ }17391739+ return ret;22951740}2296174122971742static int···23301747 return ftrace_match(str, regex, len, type);23311748}2332174923332333-static int match_records(char *buff, int len, char *mod, int enable, int not)17501750+static int17511751+match_records(struct ftrace_hash *hash, char *buff,17521752+ int len, char *mod, int not)23341753{23351754 unsigned search_len = 0;23361755 struct ftrace_page *pg;23371756 struct dyn_ftrace *rec;23381757 int type = MATCH_FULL;23391758 char *search = buff;23402340- unsigned long flag;23411759 int found = 0;17601760+ int ret;2342176123431762 if (len) {23441763 type = filter_parse_regex(buff, len, &search, ¬);23451764 search_len = strlen(search);23461765 }23472347-23482348- flag = enable ? FTRACE_FL_FILTER : FTRACE_FL_NOTRACE;2349176623501767 mutex_lock(&ftrace_lock);23511768···23551772 do_for_each_ftrace_rec(pg, rec) {2356177323571774 if (ftrace_match_record(rec, mod, search, search_len, type)) {23582358- update_record(rec, flag, not);17751775+ ret = enter_record(hash, rec, not);17761776+ if (ret < 0) {17771777+ found = ret;17781778+ goto out_unlock;17791779+ }23591780 found = 1;23601781 }23612361- /*23622362- * Only enable filtering if we have a function that23632363- * is filtered on.23642364- */23652365- if (enable && (rec->flags & FTRACE_FL_FILTER))23662366- ftrace_filtered = 1;23672367-23681782 } while_for_each_ftrace_rec();23691783 out_unlock:23701784 mutex_unlock(&ftrace_lock);···23701790}2371179123721792static int23732373-ftrace_match_records(char *buff, int len, int enable)17931793+ftrace_match_records(struct ftrace_hash *hash, char *buff, int len)23741794{23752375- return match_records(buff, len, NULL, enable, 0);17951795+ return match_records(hash, buff, len, NULL, 0);23761796}2377179723782378-static int ftrace_match_module_records(char *buff, char *mod, int enable)17981798+static int17991799+ftrace_match_module_records(struct ftrace_hash *hash, char *buff, char *mod)23791800{23801801 int not = 0;23811802···23901809 not = 1;23911810 }2392181123932393- return match_records(buff, strlen(buff), mod, enable, not);18121812+ return match_records(hash, buff, strlen(buff), mod, not);23941813}2395181423961815/*···24011820static int24021821ftrace_mod_callback(char *func, char *cmd, char *param, int enable)24031822{18231823+ struct ftrace_ops *ops = &global_ops;18241824+ struct ftrace_hash *hash;24041825 char *mod;18261826+ int ret = -EINVAL;2405182724061828 /*24071829 * cmd == 'mod' because we only registered this func···2416183224171833 /* we must have a module name */24181834 if (!param)24192419- return -EINVAL;18351835+ return ret;2420183624211837 mod = strsep(¶m, ":");24221838 if (!strlen(mod))24232423- return -EINVAL;18391839+ return ret;2424184024252425- if (ftrace_match_module_records(func, mod, enable))24262426- return 0;24272427- return -EINVAL;18411841+ if (enable)18421842+ hash = ops->filter_hash;18431843+ else18441844+ hash = ops->notrace_hash;18451845+18461846+ ret = ftrace_match_module_records(hash, func, mod);18471847+ if (!ret)18481848+ ret = -EINVAL;18491849+ if (ret < 0)18501850+ return ret;18511851+18521852+ return 0;24281853}2429185424301855static struct ftrace_func_command ftrace_mod_cmd = {···2484189124851892static void __enable_ftrace_function_probe(void)24861893{18941894+ int ret;24871895 int i;2488189624891897 if (ftrace_probe_registered)···24991905 if (i == FTRACE_FUNC_HASHSIZE)25001906 return;2501190725022502- __register_ftrace_function(&trace_probe_ops);25032503- ftrace_startup(0);19081908+ ret = __register_ftrace_function(&trace_probe_ops);19091909+ if (!ret)19101910+ ftrace_startup(&trace_probe_ops, 0);19111911+25041912 ftrace_probe_registered = 1;25051913}2506191425071915static void __disable_ftrace_function_probe(void)25081916{19171917+ int ret;25091918 int i;2510191925111920 if (!ftrace_probe_registered)···25211924 }2522192525231926 /* no more funcs left */25242524- __unregister_ftrace_function(&trace_probe_ops);25252525- ftrace_shutdown(0);19271927+ ret = __unregister_ftrace_function(&trace_probe_ops);19281928+ if (!ret)19291929+ ftrace_shutdown(&trace_probe_ops, 0);19301930+25261931 ftrace_probe_registered = 0;25271932}25281933···27272128 return ret;27282129}2729213027302730-static int ftrace_process_regex(char *buff, int len, int enable)21312131+static int ftrace_process_regex(struct ftrace_hash *hash,21322132+ char *buff, int len, int enable)27312133{27322134 char *func, *command, *next = buff;27332135 struct ftrace_func_command *p;27342734- int ret = -EINVAL;21362136+ int ret;2735213727362138 func = strsep(&next, ":");2737213927382140 if (!next) {27392739- if (ftrace_match_records(func, len, enable))27402740- return 0;27412741- return ret;21412141+ ret = ftrace_match_records(hash, func, len);21422142+ if (!ret)21432143+ ret = -EINVAL;21442144+ if (ret < 0)21452145+ return ret;21462146+ return 0;27422147 }2743214827442149 /* command found */···2790218727912188 if (read >= 0 && trace_parser_loaded(parser) &&27922189 !trace_parser_cont(parser)) {27932793- ret = ftrace_process_regex(parser->buffer,21902190+ ret = ftrace_process_regex(iter->hash, parser->buffer,27942191 parser->idx, enable);27952192 trace_parser_clear(parser);27962193 if (ret)···28182215 return ftrace_regex_write(file, ubuf, cnt, ppos, 0);28192216}2820221728212821-static void28222822-ftrace_set_regex(unsigned char *buf, int len, int reset, int enable)22182218+static int22192219+ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,22202220+ int reset, int enable)28232221{22222222+ struct ftrace_hash **orig_hash;22232223+ struct ftrace_hash *hash;22242224+ int ret;22252225+22262226+ /* All global ops uses the global ops filters */22272227+ if (ops->flags & FTRACE_OPS_FL_GLOBAL)22282228+ ops = &global_ops;22292229+28242230 if (unlikely(ftrace_disabled))28252825- return;22312231+ return -ENODEV;22322232+22332233+ if (enable)22342234+ orig_hash = &ops->filter_hash;22352235+ else22362236+ orig_hash = &ops->notrace_hash;22372237+22382238+ hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, *orig_hash);22392239+ if (!hash)22402240+ return -ENOMEM;2826224128272242 mutex_lock(&ftrace_regex_lock);28282243 if (reset)28292829- ftrace_filter_reset(enable);22442244+ ftrace_filter_reset(hash);28302245 if (buf)28312831- ftrace_match_records(buf, len, enable);22462246+ ftrace_match_records(hash, buf, len);22472247+22482248+ mutex_lock(&ftrace_lock);22492249+ ret = ftrace_hash_move(orig_hash, hash);22502250+ mutex_unlock(&ftrace_lock);22512251+28322252 mutex_unlock(&ftrace_regex_lock);22532253+22542254+ free_ftrace_hash(hash);22552255+ return ret;28332256}2834225728352258/**28362259 * ftrace_set_filter - set a function to filter on in ftrace22602260+ * @ops - the ops to set the filter with28372261 * @buf - the string that holds the function filter text.28382262 * @len - the length of the string.28392263 * @reset - non zero to reset all filters before applying this filter.···28682238 * Filters denote which functions should be enabled when tracing is enabled.28692239 * If @buf is NULL and reset is set, all functions will be enabled for tracing.28702240 */28712871-void ftrace_set_filter(unsigned char *buf, int len, int reset)22412241+void ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,22422242+ int len, int reset)28722243{28732873- ftrace_set_regex(buf, len, reset, 1);22442244+ ftrace_set_regex(ops, buf, len, reset, 1);28742245}22462246+EXPORT_SYMBOL_GPL(ftrace_set_filter);2875224728762248/**28772249 * ftrace_set_notrace - set a function to not trace in ftrace22502250+ * @ops - the ops to set the notrace filter with28782251 * @buf - the string that holds the function notrace text.28792252 * @len - the length of the string.28802253 * @reset - non zero to reset all filters before applying this filter.···28862253 * is enabled. If @buf is NULL and reset is set, all functions will be enabled28872254 * for tracing.28882255 */28892889-void ftrace_set_notrace(unsigned char *buf, int len, int reset)22562256+void ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,22572257+ int len, int reset)28902258{28912891- ftrace_set_regex(buf, len, reset, 0);22592259+ ftrace_set_regex(ops, buf, len, reset, 0);28922260}22612261+EXPORT_SYMBOL_GPL(ftrace_set_notrace);22622262+/**22632263+ * ftrace_set_filter - set a function to filter on in ftrace22642264+ * @ops - the ops to set the filter with22652265+ * @buf - the string that holds the function filter text.22662266+ * @len - the length of the string.22672267+ * @reset - non zero to reset all filters before applying this filter.22682268+ *22692269+ * Filters denote which functions should be enabled when tracing is enabled.22702270+ * If @buf is NULL and reset is set, all functions will be enabled for tracing.22712271+ */22722272+void ftrace_set_global_filter(unsigned char *buf, int len, int reset)22732273+{22742274+ ftrace_set_regex(&global_ops, buf, len, reset, 1);22752275+}22762276+EXPORT_SYMBOL_GPL(ftrace_set_global_filter);22772277+22782278+/**22792279+ * ftrace_set_notrace - set a function to not trace in ftrace22802280+ * @ops - the ops to set the notrace filter with22812281+ * @buf - the string that holds the function notrace text.22822282+ * @len - the length of the string.22832283+ * @reset - non zero to reset all filters before applying this filter.22842284+ *22852285+ * Notrace Filters denote which functions should not be enabled when tracing22862286+ * is enabled. If @buf is NULL and reset is set, all functions will be enabled22872287+ * for tracing.22882288+ */22892289+void ftrace_set_global_notrace(unsigned char *buf, int len, int reset)22902290+{22912291+ ftrace_set_regex(&global_ops, buf, len, reset, 0);22922292+}22932293+EXPORT_SYMBOL_GPL(ftrace_set_global_notrace);2893229428942295/*28952296 * command line interface to allow users to set filters on boot up.···29742307}29752308#endif /* CONFIG_FUNCTION_GRAPH_TRACER */2976230929772977-static void __init set_ftrace_early_filter(char *buf, int enable)23102310+static void __init23112311+set_ftrace_early_filter(struct ftrace_ops *ops, char *buf, int enable)29782312{29792313 char *func;2980231429812315 while (buf) {29822316 func = strsep(&buf, ",");29832983- ftrace_set_regex(func, strlen(func), 0, enable);23172317+ ftrace_set_regex(ops, func, strlen(func), 0, enable);29842318 }29852319}2986232029872321static void __init set_ftrace_early_filters(void)29882322{29892323 if (ftrace_filter_buf[0])29902990- set_ftrace_early_filter(ftrace_filter_buf, 1);23242324+ set_ftrace_early_filter(&global_ops, ftrace_filter_buf, 1);29912325 if (ftrace_notrace_buf[0])29922992- set_ftrace_early_filter(ftrace_notrace_buf, 0);23262326+ set_ftrace_early_filter(&global_ops, ftrace_notrace_buf, 0);29932327#ifdef CONFIG_FUNCTION_GRAPH_TRACER29942328 if (ftrace_graph_buf[0])29952329 set_ftrace_early_graph(ftrace_graph_buf);···29982330}2999233130002332static int30013001-ftrace_regex_release(struct inode *inode, struct file *file, int enable)23332333+ftrace_regex_release(struct inode *inode, struct file *file)30022334{30032335 struct seq_file *m = (struct seq_file *)file->private_data;30042336 struct ftrace_iterator *iter;23372337+ struct ftrace_hash **orig_hash;30052338 struct trace_parser *parser;23392339+ int filter_hash;23402340+ int ret;3006234130072342 mutex_lock(&ftrace_regex_lock);30082343 if (file->f_mode & FMODE_READ) {···30182347 parser = &iter->parser;30192348 if (trace_parser_loaded(parser)) {30202349 parser->buffer[parser->idx] = 0;30213021- ftrace_match_records(parser->buffer, parser->idx, enable);23502350+ ftrace_match_records(iter->hash, parser->buffer, parser->idx);30222351 }3023235230242353 trace_parser_put(parser);30253025- kfree(iter);3026235430272355 if (file->f_mode & FMODE_WRITE) {23562356+ filter_hash = !!(iter->flags & FTRACE_ITER_FILTER);23572357+23582358+ if (filter_hash)23592359+ orig_hash = &iter->ops->filter_hash;23602360+ else23612361+ orig_hash = &iter->ops->notrace_hash;23622362+30282363 mutex_lock(&ftrace_lock);30293029- if (ftrace_start_up && ftrace_enabled)30303030- ftrace_run_update_code(FTRACE_ENABLE_CALLS);23642364+ /*23652365+ * Remove the current set, update the hash and add23662366+ * them back.23672367+ */23682368+ ftrace_hash_rec_disable(iter->ops, filter_hash);23692369+ ret = ftrace_hash_move(orig_hash, iter->hash);23702370+ if (!ret) {23712371+ ftrace_hash_rec_enable(iter->ops, filter_hash);23722372+ if (iter->ops->flags & FTRACE_OPS_FL_ENABLED23732373+ && ftrace_enabled)23742374+ ftrace_run_update_code(FTRACE_ENABLE_CALLS);23752375+ }30312376 mutex_unlock(&ftrace_lock);30322377 }23782378+ free_ftrace_hash(iter->hash);23792379+ kfree(iter);3033238030342381 mutex_unlock(&ftrace_regex_lock);30352382 return 0;30362383}3037238430383038-static int30393039-ftrace_filter_release(struct inode *inode, struct file *file)30403040-{30413041- return ftrace_regex_release(inode, file, 1);30423042-}30433043-30443044-static int30453045-ftrace_notrace_release(struct inode *inode, struct file *file)30463046-{30473047- return ftrace_regex_release(inode, file, 0);30483048-}30493049-30502385static const struct file_operations ftrace_avail_fops = {30512386 .open = ftrace_avail_open,23872387+ .read = seq_read,23882388+ .llseek = seq_lseek,23892389+ .release = seq_release_private,23902390+};23912391+23922392+static const struct file_operations ftrace_enabled_fops = {23932393+ .open = ftrace_enabled_open,30522394 .read = seq_read,30532395 .llseek = seq_lseek,30542396 .release = seq_release_private,···30722388 .read = seq_read,30732389 .write = ftrace_filter_write,30742390 .llseek = ftrace_regex_lseek,30753075- .release = ftrace_filter_release,23912391+ .release = ftrace_regex_release,30762392};3077239330782394static const struct file_operations ftrace_notrace_fops = {···30802396 .read = seq_read,30812397 .write = ftrace_notrace_write,30822398 .llseek = ftrace_regex_lseek,30833083- .release = ftrace_notrace_release,23992399+ .release = ftrace_regex_release,30842400};3085240130862402#ifdef CONFIG_FUNCTION_GRAPH_TRACER···32982614 trace_create_file("available_filter_functions", 0444,32992615 d_tracer, NULL, &ftrace_avail_fops);3300261626172617+ trace_create_file("enabled_functions", 0444,26182618+ d_tracer, NULL, &ftrace_enabled_fops);26192619+33012620 trace_create_file("set_ftrace_filter", 0644, d_tracer,33022621 NULL, &ftrace_filter_fops);33032622···3452276534532766#else3454276727682768+static struct ftrace_ops global_ops = {27692769+ .func = ftrace_stub,27702770+};27712771+34552772static int __init ftrace_nodyn_init(void)34562773{34572774 ftrace_enabled = 1;···34662775static inline int ftrace_init_dyn_debugfs(struct dentry *d_tracer) { return 0; }34672776static inline void ftrace_startup_enable(int command) { }34682777/* Keep as macros so we do not need to define the commands */34693469-# define ftrace_startup(command) do { } while (0)34703470-# define ftrace_shutdown(command) do { } while (0)27782778+# define ftrace_startup(ops, command) do { } while (0)27792779+# define ftrace_shutdown(ops, command) do { } while (0)34712780# define ftrace_startup_sysctl() do { } while (0)34722781# define ftrace_shutdown_sysctl() do { } while (0)27822782+27832783+static inline int27842784+ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip)27852785+{27862786+ return 1;27872787+}27882788+34732789#endif /* CONFIG_DYNAMIC_FTRACE */27902790+27912791+static void27922792+ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip)27932793+{27942794+ struct ftrace_ops *op;27952795+27962796+ /*27972797+ * Some of the ops may be dynamically allocated,27982798+ * they must be freed after a synchronize_sched().27992799+ */28002800+ preempt_disable_notrace();28012801+ op = rcu_dereference_raw(ftrace_ops_list);28022802+ while (op != &ftrace_list_end) {28032803+ if (ftrace_ops_test(op, ip))28042804+ op->func(ip, parent_ip);28052805+ op = rcu_dereference_raw(op->next);28062806+ };28072807+ preempt_enable_notrace();28082808+}3474280934752810static void clear_ftrace_swapper(void)34762811{···37983081 goto out_unlock;3799308238003083 ret = __register_ftrace_function(ops);38013801- ftrace_startup(0);30843084+ if (!ret)30853085+ ftrace_startup(ops, 0);30863086+3802308738033088 out_unlock:38043089 mutex_unlock(&ftrace_lock);38053090 return ret;38063091}30923092+EXPORT_SYMBOL_GPL(register_ftrace_function);3807309338083094/**38093095 * unregister_ftrace_function - unregister a function for profiling.···3820310038213101 mutex_lock(&ftrace_lock);38223102 ret = __unregister_ftrace_function(ops);38233823- ftrace_shutdown(0);31033103+ if (!ret)31043104+ ftrace_shutdown(ops, 0);38243105 mutex_unlock(&ftrace_lock);3825310638263107 return ret;38273108}31093109+EXPORT_SYMBOL_GPL(unregister_ftrace_function);3828311038293111int38303112ftrace_enable_sysctl(struct ctl_table *table, int write,···38523130 ftrace_startup_sysctl();3853313138543132 /* we are starting ftrace again */38553855- if (ftrace_list != &ftrace_list_end) {38563856- if (ftrace_list->next == &ftrace_list_end)38573857- ftrace_trace_function = ftrace_list->func;31333133+ if (ftrace_ops_list != &ftrace_list_end) {31343134+ if (ftrace_ops_list->next == &ftrace_list_end)31353135+ ftrace_trace_function = ftrace_ops_list->func;38583136 else38593859- ftrace_trace_function = ftrace_list_func;31373137+ ftrace_trace_function = ftrace_ops_list_func;38603138 }3861313938623140 } else {···40453323 ftrace_graph_return = retfunc;40463324 ftrace_graph_entry = entryfunc;4047332540484048- ftrace_startup(FTRACE_START_FUNC_RET);33263326+ ftrace_startup(&global_ops, FTRACE_START_FUNC_RET);4049332740503328out:40513329 mutex_unlock(&ftrace_lock);···40623340 ftrace_graph_active--;40633341 ftrace_graph_return = (trace_func_graph_ret_t)ftrace_stub;40643342 ftrace_graph_entry = ftrace_graph_entry_stub;40654065- ftrace_shutdown(FTRACE_STOP_FUNC_RET);33433343+ ftrace_shutdown(&global_ops, FTRACE_STOP_FUNC_RET);40663344 unregister_pm_notifier(&ftrace_suspend_notifier);40673345 unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);40683346
+2
kernel/trace/trace.h
···419419extern unsigned long ftrace_update_tot_cnt;420420#define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func421421extern int DYN_FTRACE_TEST_NAME(void);422422+#define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2423423+extern int DYN_FTRACE_TEST_NAME2(void);422424#endif423425424426extern int ring_buffer_expanded;