|
@@ -280,10 +280,51 @@ static int ds_selftest_bts_bad_release_noirq(int cpu,
|
|
|
return error ? 0 : -1;
|
|
|
}
|
|
|
|
|
|
+static int ds_selftest_bts_bad_request_cpu(int cpu, void *buffer)
|
|
|
+{
|
|
|
+ struct bts_tracer *tracer;
|
|
|
+ int error;
|
|
|
+
|
|
|
+ /* Try to request cpu tracing while task tracing is active. */
|
|
|
+ tracer = ds_request_bts_cpu(cpu, buffer, BUFFER_SIZE, NULL,
|
|
|
+ (size_t)-1, BTS_KERNEL);
|
|
|
+ error = PTR_ERR(tracer);
|
|
|
+ if (!IS_ERR(tracer)) {
|
|
|
+ ds_release_bts(tracer);
|
|
|
+ error = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (error != -EPERM)
|
|
|
+ printk(KERN_CONT "cpu/task tracing overlap...");
|
|
|
+
|
|
|
+ return error ? 0 : -1;
|
|
|
+}
|
|
|
+
|
|
|
+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];
|
|
|
+ unsigned long irq;
|
|
|
int cpu;
|
|
|
|
|
|
printk(KERN_INFO "[ds] bts selftest...");
|
|
@@ -297,6 +338,8 @@ int ds_selftest_bts(void)
|
|
|
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;
|
|
@@ -315,12 +358,40 @@ int ds_selftest_bts(void)
|
|
|
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, buffer, 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();
|