diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2016-11-26 18:13:34 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-12-01 18:52:34 -0500 |
commit | b32614c03413f8a6025d8677c2b7c0ee976e63d4 (patch) | |
tree | 31033ddc3ce2320c4f4faec012b7bfec6199b550 | |
parent | 14660b7ea3ca628410bb999d53926ca77973892b (diff) |
tracing/rb: Convert to hotplug state machine
Install the callbacks via the state machine. The notifier in struct
ring_buffer is replaced by the multi instance interface. Upon
__ring_buffer_alloc() invocation, cpuhp_state_add_instance() will invoke
the trace_rb_cpu_prepare() on each CPU.
This callback may now fail. This means __ring_buffer_alloc() will fail and
cleanup (like previously) and during a CPU up event this failure will not
allow the CPU to come up.
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: rt@linutronix.de
Link: http://lkml.kernel.org/r/20161126231350.10321-7-bigeasy@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r-- | include/linux/cpuhotplug.h | 1 | ||||
-rw-r--r-- | include/linux/ring_buffer.h | 6 | ||||
-rw-r--r-- | kernel/trace/ring_buffer.c | 135 | ||||
-rw-r--r-- | kernel/trace/trace.c | 15 |
4 files changed, 66 insertions, 91 deletions
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index e3771fb959c0..18bcfeb2463e 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h | |||
@@ -62,6 +62,7 @@ enum cpuhp_state { | |||
62 | CPUHP_TOPOLOGY_PREPARE, | 62 | CPUHP_TOPOLOGY_PREPARE, |
63 | CPUHP_NET_IUCV_PREPARE, | 63 | CPUHP_NET_IUCV_PREPARE, |
64 | CPUHP_ARM_BL_PREPARE, | 64 | CPUHP_ARM_BL_PREPARE, |
65 | CPUHP_TRACE_RB_PREPARE, | ||
65 | CPUHP_TIMERS_DEAD, | 66 | CPUHP_TIMERS_DEAD, |
66 | CPUHP_NOTF_ERR_INJ_PREPARE, | 67 | CPUHP_NOTF_ERR_INJ_PREPARE, |
67 | CPUHP_MIPS_SOC_PREPARE, | 68 | CPUHP_MIPS_SOC_PREPARE, |
diff --git a/include/linux/ring_buffer.h b/include/linux/ring_buffer.h index 4acc552e9279..b6d4568795a7 100644 --- a/include/linux/ring_buffer.h +++ b/include/linux/ring_buffer.h | |||
@@ -198,4 +198,10 @@ enum ring_buffer_flags { | |||
198 | RB_FL_OVERWRITE = 1 << 0, | 198 | RB_FL_OVERWRITE = 1 << 0, |
199 | }; | 199 | }; |
200 | 200 | ||
201 | #ifdef CONFIG_RING_BUFFER | ||
202 | int trace_rb_cpu_prepare(unsigned int cpu, struct hlist_node *node); | ||
203 | #else | ||
204 | #define trace_rb_cpu_prepare NULL | ||
205 | #endif | ||
206 | |||
201 | #endif /* _LINUX_RING_BUFFER_H */ | 207 | #endif /* _LINUX_RING_BUFFER_H */ |
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c index 9c143739b8d7..a7a055f167c7 100644 --- a/kernel/trace/ring_buffer.c +++ b/kernel/trace/ring_buffer.c | |||
@@ -479,9 +479,7 @@ struct ring_buffer { | |||
479 | 479 | ||
480 | struct ring_buffer_per_cpu **buffers; | 480 | struct ring_buffer_per_cpu **buffers; |
481 | 481 | ||
482 | #ifdef CONFIG_HOTPLUG_CPU | 482 | struct hlist_node node; |
483 | struct notifier_block cpu_notify; | ||
484 | #endif | ||
485 | u64 (*clock)(void); | 483 | u64 (*clock)(void); |
486 | 484 | ||
487 | struct rb_irq_work irq_work; | 485 | struct rb_irq_work irq_work; |
@@ -1274,11 +1272,6 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer) | |||
1274 | kfree(cpu_buffer); | 1272 | kfree(cpu_buffer); |
1275 | } | 1273 | } |
1276 | 1274 | ||
1277 | #ifdef CONFIG_HOTPLUG_CPU | ||
1278 | static int rb_cpu_notify(struct notifier_block *self, | ||
1279 | unsigned long action, void *hcpu); | ||
1280 | #endif | ||
1281 | |||
1282 | /** | 1275 | /** |
1283 | * __ring_buffer_alloc - allocate a new ring_buffer | 1276 | * __ring_buffer_alloc - allocate a new ring_buffer |
1284 | * @size: the size in bytes per cpu that is needed. | 1277 | * @size: the size in bytes per cpu that is needed. |
@@ -1296,6 +1289,7 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags, | |||
1296 | long nr_pages; | 1289 | long nr_pages; |
1297 | int bsize; | 1290 | int bsize; |
1298 | int cpu; | 1291 | int cpu; |
1292 | int ret; | ||
1299 | 1293 | ||
1300 | /* keep it in its own cache line */ | 1294 | /* keep it in its own cache line */ |
1301 | buffer = kzalloc(ALIGN(sizeof(*buffer), cache_line_size()), | 1295 | buffer = kzalloc(ALIGN(sizeof(*buffer), cache_line_size()), |
@@ -1318,17 +1312,6 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags, | |||
1318 | if (nr_pages < 2) | 1312 | if (nr_pages < 2) |
1319 | nr_pages = 2; | 1313 | nr_pages = 2; |
1320 | 1314 | ||
1321 | /* | ||
1322 | * In case of non-hotplug cpu, if the ring-buffer is allocated | ||
1323 | * in early initcall, it will not be notified of secondary cpus. | ||
1324 | * In that off case, we need to allocate for all possible cpus. | ||
1325 | */ | ||
1326 | #ifdef CONFIG_HOTPLUG_CPU | ||
1327 | cpu_notifier_register_begin(); | ||
1328 | cpumask_copy(buffer->cpumask, cpu_online_mask); | ||
1329 | #else | ||
1330 | cpumask_copy(buffer->cpumask, cpu_possible_mask); | ||
1331 | #endif | ||
1332 | buffer->cpus = nr_cpu_ids; | 1315 | buffer->cpus = nr_cpu_ids; |
1333 | 1316 | ||
1334 | bsize = sizeof(void *) * nr_cpu_ids; | 1317 | bsize = sizeof(void *) * nr_cpu_ids; |
@@ -1337,19 +1320,15 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags, | |||
1337 | if (!buffer->buffers) | 1320 | if (!buffer->buffers) |
1338 | goto fail_free_cpumask; | 1321 | goto fail_free_cpumask; |
1339 | 1322 | ||
1340 | for_each_buffer_cpu(buffer, cpu) { | 1323 | cpu = raw_smp_processor_id(); |
1341 | buffer->buffers[cpu] = | 1324 | cpumask_set_cpu(cpu, buffer->cpumask); |
1342 | rb_allocate_cpu_buffer(buffer, nr_pages, cpu); | 1325 | buffer->buffers[cpu] = rb_allocate_cpu_buffer(buffer, nr_pages, cpu); |
1343 | if (!buffer->buffers[cpu]) | 1326 | if (!buffer->buffers[cpu]) |
1344 | goto fail_free_buffers; | 1327 | goto fail_free_buffers; |
1345 | } | ||
1346 | 1328 | ||
1347 | #ifdef CONFIG_HOTPLUG_CPU | 1329 | ret = cpuhp_state_add_instance(CPUHP_TRACE_RB_PREPARE, &buffer->node); |
1348 | buffer->cpu_notify.notifier_call = rb_cpu_notify; | 1330 | if (ret < 0) |
1349 | buffer->cpu_notify.priority = 0; | 1331 | goto fail_free_buffers; |
1350 | __register_cpu_notifier(&buffer->cpu_notify); | ||
1351 | cpu_notifier_register_done(); | ||
1352 | #endif | ||
1353 | 1332 | ||
1354 | mutex_init(&buffer->mutex); | 1333 | mutex_init(&buffer->mutex); |
1355 | 1334 | ||
@@ -1364,9 +1343,6 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags, | |||
1364 | 1343 | ||
1365 | fail_free_cpumask: | 1344 | fail_free_cpumask: |
1366 | free_cpumask_var(buffer->cpumask); | 1345 | free_cpumask_var(buffer->cpumask); |
1367 | #ifdef CONFIG_HOTPLUG_CPU | ||
1368 | cpu_notifier_register_done(); | ||
1369 | #endif | ||
1370 | 1346 | ||
1371 | fail_free_buffer: | 1347 | fail_free_buffer: |
1372 | kfree(buffer); | 1348 | kfree(buffer); |
@@ -1383,18 +1359,11 @@ ring_buffer_free(struct ring_buffer *buffer) | |||
1383 | { | 1359 | { |
1384 | int cpu; | 1360 | int cpu; |
1385 | 1361 | ||
1386 | #ifdef CONFIG_HOTPLUG_CPU | 1362 | cpuhp_state_remove_instance(CPUHP_TRACE_RB_PREPARE, &buffer->node); |
1387 | cpu_notifier_register_begin(); | ||
1388 | __unregister_cpu_notifier(&buffer->cpu_notify); | ||
1389 | #endif | ||
1390 | 1363 | ||
1391 | for_each_buffer_cpu(buffer, cpu) | 1364 | for_each_buffer_cpu(buffer, cpu) |
1392 | rb_free_cpu_buffer(buffer->buffers[cpu]); | 1365 | rb_free_cpu_buffer(buffer->buffers[cpu]); |
1393 | 1366 | ||
1394 | #ifdef CONFIG_HOTPLUG_CPU | ||
1395 | cpu_notifier_register_done(); | ||
1396 | #endif | ||
1397 | |||
1398 | kfree(buffer->buffers); | 1367 | kfree(buffer->buffers); |
1399 | free_cpumask_var(buffer->cpumask); | 1368 | free_cpumask_var(buffer->cpumask); |
1400 | 1369 | ||
@@ -4633,62 +4602,48 @@ int ring_buffer_read_page(struct ring_buffer *buffer, | |||
4633 | } | 4602 | } |
4634 | EXPORT_SYMBOL_GPL(ring_buffer_read_page); | 4603 | EXPORT_SYMBOL_GPL(ring_buffer_read_page); |
4635 | 4604 | ||
4636 | #ifdef CONFIG_HOTPLUG_CPU | 4605 | /* |
4637 | static int rb_cpu_notify(struct notifier_block *self, | 4606 | * We only allocate new buffers, never free them if the CPU goes down. |
4638 | unsigned long action, void *hcpu) | 4607 | * If we were to free the buffer, then the user would lose any trace that was in |
4608 | * the buffer. | ||
4609 | */ | ||
4610 | int trace_rb_cpu_prepare(unsigned int cpu, struct hlist_node *node) | ||
4639 | { | 4611 | { |
4640 | struct ring_buffer *buffer = | 4612 | struct ring_buffer *buffer; |
4641 | container_of(self, struct ring_buffer, cpu_notify); | ||
4642 | long cpu = (long)hcpu; | ||
4643 | long nr_pages_same; | 4613 | long nr_pages_same; |
4644 | int cpu_i; | 4614 | int cpu_i; |
4645 | unsigned long nr_pages; | 4615 | unsigned long nr_pages; |
4646 | 4616 | ||
4647 | switch (action) { | 4617 | buffer = container_of(node, struct ring_buffer, node); |
4648 | case CPU_UP_PREPARE: | 4618 | if (cpumask_test_cpu(cpu, buffer->cpumask)) |
4649 | case CPU_UP_PREPARE_FROZEN: | 4619 | return 0; |
4650 | if (cpumask_test_cpu(cpu, buffer->cpumask)) | 4620 | |
4651 | return NOTIFY_OK; | 4621 | nr_pages = 0; |
4652 | 4622 | nr_pages_same = 1; | |
4653 | nr_pages = 0; | 4623 | /* check if all cpu sizes are same */ |
4654 | nr_pages_same = 1; | 4624 | for_each_buffer_cpu(buffer, cpu_i) { |
4655 | /* check if all cpu sizes are same */ | 4625 | /* fill in the size from first enabled cpu */ |
4656 | for_each_buffer_cpu(buffer, cpu_i) { | 4626 | if (nr_pages == 0) |
4657 | /* fill in the size from first enabled cpu */ | 4627 | nr_pages = buffer->buffers[cpu_i]->nr_pages; |
4658 | if (nr_pages == 0) | 4628 | if (nr_pages != buffer->buffers[cpu_i]->nr_pages) { |
4659 | nr_pages = buffer->buffers[cpu_i]->nr_pages; | 4629 | nr_pages_same = 0; |
4660 | if (nr_pages != buffer->buffers[cpu_i]->nr_pages) { | 4630 | break; |
4661 | nr_pages_same = 0; | ||
4662 | break; | ||
4663 | } | ||
4664 | } | ||
4665 | /* allocate minimum pages, user can later expand it */ | ||
4666 | if (!nr_pages_same) | ||
4667 | nr_pages = 2; | ||
4668 | buffer->buffers[cpu] = | ||
4669 | rb_allocate_cpu_buffer(buffer, nr_pages, cpu); | ||
4670 | if (!buffer->buffers[cpu]) { | ||
4671 | WARN(1, "failed to allocate ring buffer on CPU %ld\n", | ||
4672 | cpu); | ||
4673 | return NOTIFY_OK; | ||
4674 | } | 4631 | } |
4675 | smp_wmb(); | ||
4676 | cpumask_set_cpu(cpu, buffer->cpumask); | ||
4677 | break; | ||
4678 | case CPU_DOWN_PREPARE: | ||
4679 | case CPU_DOWN_PREPARE_FROZEN: | ||
4680 | /* | ||
4681 | * Do nothing. | ||
4682 | * If we were to free the buffer, then the user would | ||
4683 | * lose any trace that was in the buffer. | ||
4684 | */ | ||
4685 | break; | ||
4686 | default: | ||
4687 | break; | ||
4688 | } | 4632 | } |
4689 | return NOTIFY_OK; | 4633 | /* allocate minimum pages, user can later expand it */ |
4634 | if (!nr_pages_same) | ||
4635 | nr_pages = 2; | ||
4636 | buffer->buffers[cpu] = | ||
4637 | rb_allocate_cpu_buffer(buffer, nr_pages, cpu); | ||
4638 | if (!buffer->buffers[cpu]) { | ||
4639 | WARN(1, "failed to allocate ring buffer on CPU %u\n", | ||
4640 | cpu); | ||
4641 | return -ENOMEM; | ||
4642 | } | ||
4643 | smp_wmb(); | ||
4644 | cpumask_set_cpu(cpu, buffer->cpumask); | ||
4645 | return 0; | ||
4690 | } | 4646 | } |
4691 | #endif | ||
4692 | 4647 | ||
4693 | #ifdef CONFIG_RING_BUFFER_STARTUP_TEST | 4648 | #ifdef CONFIG_RING_BUFFER_STARTUP_TEST |
4694 | /* | 4649 | /* |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 8696ce6bf2f6..465d56febc5b 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -7659,10 +7659,21 @@ __init static int tracer_alloc_buffers(void) | |||
7659 | 7659 | ||
7660 | raw_spin_lock_init(&global_trace.start_lock); | 7660 | raw_spin_lock_init(&global_trace.start_lock); |
7661 | 7661 | ||
7662 | /* | ||
7663 | * The prepare callbacks allocates some memory for the ring buffer. We | ||
7664 | * don't free the buffer if the if the CPU goes down. If we were to free | ||
7665 | * the buffer, then the user would lose any trace that was in the | ||
7666 | * buffer. The memory will be removed once the "instance" is removed. | ||
7667 | */ | ||
7668 | ret = cpuhp_setup_state_multi(CPUHP_TRACE_RB_PREPARE, | ||
7669 | "trace/RB:preapre", trace_rb_cpu_prepare, | ||
7670 | NULL); | ||
7671 | if (ret < 0) | ||
7672 | goto out_free_cpumask; | ||
7662 | /* Used for event triggers */ | 7673 | /* Used for event triggers */ |
7663 | temp_buffer = ring_buffer_alloc(PAGE_SIZE, RB_FL_OVERWRITE); | 7674 | temp_buffer = ring_buffer_alloc(PAGE_SIZE, RB_FL_OVERWRITE); |
7664 | if (!temp_buffer) | 7675 | if (!temp_buffer) |
7665 | goto out_free_cpumask; | 7676 | goto out_rm_hp_state; |
7666 | 7677 | ||
7667 | if (trace_create_savedcmd() < 0) | 7678 | if (trace_create_savedcmd() < 0) |
7668 | goto out_free_temp_buffer; | 7679 | goto out_free_temp_buffer; |
@@ -7723,6 +7734,8 @@ out_free_savedcmd: | |||
7723 | free_saved_cmdlines_buffer(savedcmd); | 7734 | free_saved_cmdlines_buffer(savedcmd); |
7724 | out_free_temp_buffer: | 7735 | out_free_temp_buffer: |
7725 | ring_buffer_free(temp_buffer); | 7736 | ring_buffer_free(temp_buffer); |
7737 | out_rm_hp_state: | ||
7738 | cpuhp_remove_multi_state(CPUHP_TRACE_RB_PREPARE); | ||
7726 | out_free_cpumask: | 7739 | out_free_cpumask: |
7727 | free_cpumask_var(global_trace.tracing_cpumask); | 7740 | free_cpumask_var(global_trace.tracing_cpumask); |
7728 | out_free_buffer_mask: | 7741 | out_free_buffer_mask: |