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-v7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace

Pull tracing fixes from Steven Rostedt:

- Fix potential deadlock in osnoise and hotplug

The interface_lock can be called by a osnoise thread and the CPU
shutdown logic of osnoise can wait for this thread to finish. But
cpus_read_lock() can also be taken while holding the interface_lock.
This produces a circular lock dependency and can cause a deadlock.

Swap the ordering of cpus_read_lock() and the interface_lock to have
interface_lock taken within the cpus_read_lock() context to prevent
this circular dependency.

- Fix freeing of event triggers in early boot up

If the same trigger is added on the kernel command line, the second
one will fail to be applied and the trigger created will be freed.
This calls into the deferred logic and creates a kernel thread to do
the freeing. But the command line logic is called before kernel
threads can be created and this leads to a NULL pointer dereference.

Delay freeing event triggers until late init.

* tag 'trace-v7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
tracing: Drain deferred trigger frees if kthread creation fails
tracing: Fix potential deadlock in cpu hotplug with osnoise

+74 -21
+69 -16
kernel/trace/trace_events_trigger.c
··· 22 22 static struct llist_head trigger_data_free_list; 23 23 static DEFINE_MUTEX(trigger_data_kthread_mutex); 24 24 25 + static int trigger_kthread_fn(void *ignore); 26 + 27 + static void trigger_create_kthread_locked(void) 28 + { 29 + lockdep_assert_held(&trigger_data_kthread_mutex); 30 + 31 + if (!trigger_kthread) { 32 + struct task_struct *kthread; 33 + 34 + kthread = kthread_create(trigger_kthread_fn, NULL, 35 + "trigger_data_free"); 36 + if (!IS_ERR(kthread)) 37 + WRITE_ONCE(trigger_kthread, kthread); 38 + } 39 + } 40 + 41 + static void trigger_data_free_queued_locked(void) 42 + { 43 + struct event_trigger_data *data, *tmp; 44 + struct llist_node *llnodes; 45 + 46 + lockdep_assert_held(&trigger_data_kthread_mutex); 47 + 48 + llnodes = llist_del_all(&trigger_data_free_list); 49 + if (!llnodes) 50 + return; 51 + 52 + tracepoint_synchronize_unregister(); 53 + 54 + llist_for_each_entry_safe(data, tmp, llnodes, llist) 55 + kfree(data); 56 + } 57 + 25 58 /* Bulk garbage collection of event_trigger_data elements */ 26 59 static int trigger_kthread_fn(void *ignore) 27 60 { ··· 89 56 if (data->cmd_ops->set_filter) 90 57 data->cmd_ops->set_filter(NULL, data, NULL); 91 58 92 - if (unlikely(!trigger_kthread)) { 93 - guard(mutex)(&trigger_data_kthread_mutex); 94 - /* Check again after taking mutex */ 95 - if (!trigger_kthread) { 96 - struct task_struct *kthread; 97 - 98 - kthread = kthread_create(trigger_kthread_fn, NULL, 99 - "trigger_data_free"); 100 - if (!IS_ERR(kthread)) 101 - WRITE_ONCE(trigger_kthread, kthread); 102 - } 59 + /* 60 + * Boot-time trigger registration can fail before kthread creation 61 + * works. Keep the deferred-free semantics during boot and let late 62 + * init start the kthread to drain the list. 63 + */ 64 + if (system_state == SYSTEM_BOOTING && !trigger_kthread) { 65 + llist_add(&data->llist, &trigger_data_free_list); 66 + return; 103 67 } 104 68 105 - if (!trigger_kthread) { 106 - /* Do it the slow way */ 107 - tracepoint_synchronize_unregister(); 108 - kfree(data); 109 - return; 69 + if (unlikely(!trigger_kthread)) { 70 + guard(mutex)(&trigger_data_kthread_mutex); 71 + 72 + trigger_create_kthread_locked(); 73 + /* Check again after taking mutex */ 74 + if (!trigger_kthread) { 75 + llist_add(&data->llist, &trigger_data_free_list); 76 + /* Drain the queued frees synchronously if creation failed. */ 77 + trigger_data_free_queued_locked(); 78 + return; 79 + } 110 80 } 111 81 112 82 llist_add(&data->llist, &trigger_data_free_list); 113 83 wake_up_process(trigger_kthread); 114 84 } 85 + 86 + static int __init trigger_data_free_init(void) 87 + { 88 + guard(mutex)(&trigger_data_kthread_mutex); 89 + 90 + if (llist_empty(&trigger_data_free_list)) 91 + return 0; 92 + 93 + trigger_create_kthread_locked(); 94 + if (trigger_kthread) 95 + wake_up_process(trigger_kthread); 96 + else 97 + trigger_data_free_queued_locked(); 98 + 99 + return 0; 100 + } 101 + late_initcall(trigger_data_free_init); 115 102 116 103 static inline void data_ops_trigger(struct event_trigger_data *data, 117 104 struct trace_buffer *buffer, void *rec,
+5 -5
kernel/trace/trace_osnoise.c
··· 2073 2073 if (!osnoise_has_registered_instances()) 2074 2074 return; 2075 2075 2076 - guard(mutex)(&interface_lock); 2077 2076 guard(cpus_read_lock)(); 2077 + guard(mutex)(&interface_lock); 2078 2078 2079 2079 if (!cpu_online(cpu)) 2080 2080 return; ··· 2237 2237 if (running) 2238 2238 stop_per_cpu_kthreads(); 2239 2239 2240 - mutex_lock(&interface_lock); 2241 2240 /* 2242 2241 * avoid CPU hotplug operations that might read options. 2243 2242 */ 2244 2243 cpus_read_lock(); 2244 + mutex_lock(&interface_lock); 2245 2245 2246 2246 retval = cnt; 2247 2247 ··· 2257 2257 clear_bit(option, &osnoise_options); 2258 2258 } 2259 2259 2260 - cpus_read_unlock(); 2261 2260 mutex_unlock(&interface_lock); 2261 + cpus_read_unlock(); 2262 2262 2263 2263 if (running) 2264 2264 start_per_cpu_kthreads(); ··· 2345 2345 if (running) 2346 2346 stop_per_cpu_kthreads(); 2347 2347 2348 - mutex_lock(&interface_lock); 2349 2348 /* 2350 2349 * osnoise_cpumask is read by CPU hotplug operations. 2351 2350 */ 2352 2351 cpus_read_lock(); 2352 + mutex_lock(&interface_lock); 2353 2353 2354 2354 cpumask_copy(&osnoise_cpumask, osnoise_cpumask_new); 2355 2355 2356 - cpus_read_unlock(); 2357 2356 mutex_unlock(&interface_lock); 2357 + cpus_read_unlock(); 2358 2358 2359 2359 if (running) 2360 2360 start_per_cpu_kthreads();