/* * Stop tracing on the current cpu. * The argument is ignored. * * pre: bts_tracer_lock must be locked. */ static void bts_trace_stop_cpu(void *arg) { if (this_tracer) { ds_release_bts(this_tracer); this_tracer = NULL; } }
static int __cpuinit bts_hotcpu_handler(struct notifier_block *nfb, unsigned long action, void *hcpu) { int cpu = (long)hcpu; switch (action) { case CPU_ONLINE: case CPU_DOWN_FAILED: /* The notification is sent with interrupts enabled. */ if (trace_hw_branches_enabled) { bts_trace_init_cpu(cpu); if (trace_hw_branches_suspended && likely(per_cpu(hwb_tracer, cpu))) ds_suspend_bts(per_cpu(hwb_tracer, cpu)); } break; case CPU_DOWN_PREPARE: /* The notification is sent with interrupts enabled. */ if (likely(per_cpu(hwb_tracer, cpu))) { ds_release_bts(per_cpu(hwb_tracer, cpu)); per_cpu(hwb_tracer, cpu) = NULL; } } return NOTIFY_DONE; }
/* * Start tracing on the current cpu. * The argument is ignored. * * pre: bts_tracer_lock must be locked. */ static void bts_trace_start_cpu(void *arg) { if (this_tracer) ds_release_bts(this_tracer); this_tracer = ds_request_bts(/* task = */ NULL, this_buffer, SIZEOF_BTS, /* ovfl = */ NULL, /* th = */ (size_t)-1, BTS_KERNEL); if (IS_ERR(this_tracer)) { this_tracer = NULL; return; } }
static void bts_trace_reset(struct trace_array *tr) { int cpu; get_online_cpus(); for_each_online_cpu(cpu) { if (likely(per_cpu(hwb_tracer, cpu))) { ds_release_bts(per_cpu(hwb_tracer, cpu)); per_cpu(hwb_tracer, cpu) = NULL; } } trace_hw_branches_enabled = 0; trace_hw_branches_suspended = 0; put_online_cpus(); }
static int ds_selftest_bts_bad_request_task(void *buffer) { struct bts_tracer *tracer; int error; /* Try to request cpu tracing while task tracing is active. */ tracer = ds_request_bts_task(current, buffer, BUFFER_SIZE, NULL, (size_t)-1, BTS_KERNEL); error = PTR_ERR(tracer); if (!IS_ERR(tracer)) { error = 0; ds_release_bts(tracer); } if (error != -EPERM) printk(KERN_CONT "task/cpu tracing overlap..."); return error ? 0 : -1; }
int ds_selftest_bts(void) { struct ds_selftest_bts_conf conf; unsigned char buffer[BUFFER_SIZE], *small_buffer; unsigned long irq; int cpu; printk(KERN_INFO "[ds] bts selftest..."); conf.error = 0; small_buffer = (unsigned char *)ALIGN((unsigned long)buffer, 8) + 8; get_online_cpus(); for_each_online_cpu(cpu) { conf.suspend = ds_suspend_bts_wrap; conf.resume = ds_resume_bts_wrap; conf.tracer = ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE, NULL, (size_t)-1, BTS_KERNEL); ds_selftest_bts_cpu(&conf); if (conf.error >= 0) conf.error = ds_selftest_bts_bad_request_task(buffer); ds_release_bts(conf.tracer); if (conf.error < 0) goto out; conf.suspend = ds_suspend_bts_noirq; conf.resume = ds_resume_bts_noirq; conf.tracer = ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE, NULL, (size_t)-1, BTS_KERNEL); smp_call_function_single(cpu, ds_selftest_bts_cpu, &conf, 1); if (conf.error >= 0) { conf.error = ds_selftest_bts_bad_release_noirq(cpu, conf.tracer); /* We must not release the tracer twice. */ if (conf.error < 0) conf.tracer = NULL; } if (conf.error >= 0) conf.error = ds_selftest_bts_bad_request_task(buffer); smp_call_function_single(cpu, ds_release_bts_noirq_wrap, conf.tracer, 1); if (conf.error < 0) goto out; } conf.suspend = ds_suspend_bts_wrap; conf.resume = ds_resume_bts_wrap; conf.tracer = ds_request_bts_task(current, buffer, BUFFER_SIZE, NULL, (size_t)-1, BTS_KERNEL); ds_selftest_bts_cpu(&conf); if (conf.error >= 0) conf.error = ds_selftest_bts_bad_request_cpu(0, buffer); ds_release_bts(conf.tracer); if (conf.error < 0) goto out; conf.suspend = ds_suspend_bts_noirq; conf.resume = ds_resume_bts_noirq; conf.tracer = ds_request_bts_task(current, small_buffer, SMALL_BUFFER_SIZE, NULL, (size_t)-1, BTS_KERNEL); local_irq_save(irq); ds_selftest_bts_cpu(&conf); if (conf.error >= 0) conf.error = ds_selftest_bts_bad_request_cpu(0, buffer); ds_release_bts_noirq(conf.tracer); local_irq_restore(irq); if (conf.error < 0) goto out; conf.error = 0; out: put_online_cpus(); printk(KERN_CONT "%s.\n", (conf.error ? "failed" : "passed")); return conf.error; }