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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'trace-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull tracing updates from Steven Rostedt:

- Remove unused ftrace_direct_funcs variables

- Fix a possible NULL pointer dereference race in eventfs

- Update do_div() usage in trace event benchmark test

- Speedup direct function registration with asynchronous RCU callback.

The synchronization was done in the registration code and this caused
delays when registering direct callbacks. Move the freeing to a
call_rcu() that will prevent delaying of the registering.

- Replace simple_strtoul() usage with kstrtoul()

* tag 'trace-v6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
eventfs: Fix a possible null pointer dereference in eventfs_find_events()
ftrace: Fix possible use-after-free issue in ftrace_location()
ftrace: Remove unused global 'ftrace_direct_func_count'
ftrace: Remove unused list 'ftrace_direct_funcs'
tracing: Improve benchmark test performance by using do_div()
ftrace: Use asynchronous grace period for register_ftrace_direct()
ftrace: Replaces simple_strtoul in ftrace

+39 -52
+3 -4
fs/tracefs/event_inode.c
··· 345 345 * If the ei is being freed, the ownership of the children 346 346 * doesn't matter. 347 347 */ 348 - if (ei->is_freed) { 349 - ei = NULL; 350 - break; 351 - } 348 + if (ei->is_freed) 349 + return NULL; 350 + 352 351 // Walk upwards until you find the events inode 353 352 } while (!ei->is_events); 354 353
-3
include/linux/ftrace.h
··· 83 83 84 84 struct module; 85 85 struct ftrace_hash; 86 - struct ftrace_direct_func; 87 86 88 87 #if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_MODULES) && \ 89 88 defined(CONFIG_DYNAMIC_FTRACE) ··· 413 414 }; 414 415 415 416 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS 416 - extern int ftrace_direct_func_count; 417 417 unsigned long ftrace_find_rec_direct(unsigned long ip); 418 418 int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr); 419 419 int unregister_ftrace_direct(struct ftrace_ops *ops, unsigned long addr, ··· 424 426 425 427 #else 426 428 struct ftrace_ops; 427 - # define ftrace_direct_func_count 0 428 429 static inline unsigned long ftrace_find_rec_direct(unsigned long ip) 429 430 { 430 431 return 0;
-11
kernel/trace/fgraph.c
··· 125 125 { 126 126 struct ftrace_graph_ent trace; 127 127 128 - #ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS 129 - /* 130 - * Skip graph tracing if the return location is served by direct trampoline, 131 - * since call sequence and return addresses are unpredictable anyway. 132 - * Ex: BPF trampoline may call original function and may skip frame 133 - * depending on type of BPF programs attached. 134 - */ 135 - if (ftrace_direct_func_count && 136 - ftrace_find_rec_direct(ret - MCOUNT_INSN_SIZE)) 137 - return -EBUSY; 138 - #endif 139 128 trace.func = func; 140 129 trace.depth = ++current->curr_ret_depth; 141 130
+35 -33
kernel/trace/ftrace.c
··· 1595 1595 unsigned long ftrace_location_range(unsigned long start, unsigned long end) 1596 1596 { 1597 1597 struct dyn_ftrace *rec; 1598 + unsigned long ip = 0; 1598 1599 1600 + rcu_read_lock(); 1599 1601 rec = lookup_rec(start, end); 1600 1602 if (rec) 1601 - return rec->ip; 1603 + ip = rec->ip; 1604 + rcu_read_unlock(); 1602 1605 1603 - return 0; 1606 + return ip; 1604 1607 } 1605 1608 1606 1609 /** ··· 1617 1614 */ 1618 1615 unsigned long ftrace_location(unsigned long ip) 1619 1616 { 1620 - struct dyn_ftrace *rec; 1617 + unsigned long loc; 1621 1618 unsigned long offset; 1622 1619 unsigned long size; 1623 1620 1624 - rec = lookup_rec(ip, ip); 1625 - if (!rec) { 1621 + loc = ftrace_location_range(ip, ip); 1622 + if (!loc) { 1626 1623 if (!kallsyms_lookup_size_offset(ip, &size, &offset)) 1627 1624 goto out; 1628 1625 1629 1626 /* map sym+0 to __fentry__ */ 1630 1627 if (!offset) 1631 - rec = lookup_rec(ip, ip + size - 1); 1628 + loc = ftrace_location_range(ip, ip + size - 1); 1632 1629 } 1633 1630 1634 - if (rec) 1635 - return rec->ip; 1636 - 1637 1631 out: 1638 - return 0; 1632 + return loc; 1639 1633 } 1640 1634 1641 1635 /** ··· 2538 2538 /* Protected by rcu_tasks for reading, and direct_mutex for writing */ 2539 2539 static struct ftrace_hash __rcu *direct_functions = EMPTY_HASH; 2540 2540 static DEFINE_MUTEX(direct_mutex); 2541 - int ftrace_direct_func_count; 2542 2541 2543 2542 /* 2544 2543 * Search the direct_functions hash to see if the given instruction pointer ··· 4200 4201 add_rec_by_index(struct ftrace_hash *hash, struct ftrace_glob *func_g, 4201 4202 int clear_filter) 4202 4203 { 4203 - long index = simple_strtoul(func_g->search, NULL, 0); 4204 + long index; 4204 4205 struct ftrace_page *pg; 4205 4206 struct dyn_ftrace *rec; 4206 4207 4207 4208 /* The index starts at 1 */ 4208 - if (--index < 0) 4209 + if (kstrtoul(func_g->search, 0, &index) || --index < 0) 4209 4210 return 0; 4210 4211 4211 4212 do_for_each_ftrace_rec(pg, rec) { ··· 5316 5317 5317 5318 #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS 5318 5319 5319 - struct ftrace_direct_func { 5320 - struct list_head next; 5321 - unsigned long addr; 5322 - int count; 5323 - }; 5324 - 5325 - static LIST_HEAD(ftrace_direct_funcs); 5326 - 5327 5320 static int register_ftrace_function_nolock(struct ftrace_ops *ops); 5328 5321 5329 5322 /* ··· 5354 5363 } 5355 5364 } 5356 5365 } 5366 + } 5367 + 5368 + static void register_ftrace_direct_cb(struct rcu_head *rhp) 5369 + { 5370 + struct ftrace_hash *fhp = container_of(rhp, struct ftrace_hash, rcu); 5371 + 5372 + free_ftrace_hash(fhp); 5357 5373 } 5358 5374 5359 5375 /** ··· 5461 5463 out_unlock: 5462 5464 mutex_unlock(&direct_mutex); 5463 5465 5464 - if (free_hash && free_hash != EMPTY_HASH) { 5465 - synchronize_rcu_tasks(); 5466 - free_ftrace_hash(free_hash); 5467 - } 5466 + if (free_hash && free_hash != EMPTY_HASH) 5467 + call_rcu_tasks(&free_hash->rcu, register_ftrace_direct_cb); 5468 5468 5469 5469 if (new_hash) 5470 5470 free_ftrace_hash(new_hash); ··· 5812 5816 5813 5817 static int __init set_graph_max_depth_function(char *str) 5814 5818 { 5815 - if (!str) 5819 + if (!str || kstrtouint(str, 0, &fgraph_max_depth)) 5816 5820 return 0; 5817 - fgraph_max_depth = simple_strtoul(str, NULL, 0); 5818 5821 return 1; 5819 5822 } 5820 5823 __setup("ftrace_graph_max_depth=", set_graph_max_depth_function); ··· 6590 6595 /* We should have used all pages unless we skipped some */ 6591 6596 if (pg_unuse) { 6592 6597 WARN_ON(!skipped); 6598 + /* Need to synchronize with ftrace_location_range() */ 6599 + synchronize_rcu(); 6593 6600 ftrace_free_pages(pg_unuse); 6594 6601 } 6595 6602 return ret; ··· 6805 6808 out_unlock: 6806 6809 mutex_unlock(&ftrace_lock); 6807 6810 6811 + /* Need to synchronize with ftrace_location_range() */ 6812 + if (tmp_page) 6813 + synchronize_rcu(); 6808 6814 for (pg = tmp_page; pg; pg = tmp_page) { 6809 6815 6810 6816 /* Needs to be called outside of ftrace_lock */ ··· 7141 7141 unsigned long start = (unsigned long)(start_ptr); 7142 7142 unsigned long end = (unsigned long)(end_ptr); 7143 7143 struct ftrace_page **last_pg = &ftrace_pages_start; 7144 + struct ftrace_page *tmp_page = NULL; 7144 7145 struct ftrace_page *pg; 7145 7146 struct dyn_ftrace *rec; 7146 7147 struct dyn_ftrace key; ··· 7183 7182 ftrace_update_tot_cnt--; 7184 7183 if (!pg->index) { 7185 7184 *last_pg = pg->next; 7186 - if (pg->records) { 7187 - free_pages((unsigned long)pg->records, pg->order); 7188 - ftrace_number_of_pages -= 1 << pg->order; 7189 - } 7190 - ftrace_number_of_groups--; 7191 - kfree(pg); 7185 + pg->next = tmp_page; 7186 + tmp_page = pg; 7192 7187 pg = container_of(last_pg, struct ftrace_page, next); 7193 7188 if (!(*last_pg)) 7194 7189 ftrace_pages = pg; ··· 7200 7203 list_for_each_entry_safe(func, func_next, &clear_hash, list) { 7201 7204 clear_func_from_hashes(func); 7202 7205 kfree(func); 7206 + } 7207 + /* Need to synchronize with ftrace_location_range() */ 7208 + if (tmp_page) { 7209 + synchronize_rcu(); 7210 + ftrace_free_pages(tmp_page); 7203 7211 } 7204 7212 } 7205 7213
+1 -1
kernel/trace/trace_benchmark.c
··· 104 104 stddev = 0; 105 105 106 106 delta = bm_total; 107 - delta = div64_u64(delta, bm_cnt); 107 + do_div(delta, (u32)bm_cnt); 108 108 avg = delta; 109 109 110 110 if (stddev > 0) {