Re: call_rcu from trace_preempt
From: Daniel Wagner
Date: Tue Jun 16 2015 - 02:34:25 EST
On 06/16/2015 08:25 AM, Alexei Starovoitov wrote:
> On 6/15/15 11:06 PM, Daniel Wagner wrote:
>>> with the above 'fix' the trace.patch is now passing.
>> It still crashes for me with the original test program
>>
>> [ 145.908013] [<ffffffff810d1da1>] ? __rcu_reclaim+0x101/0x3d0
>> [ 145.908013] [<ffffffff810d1ca0>] ? rcu_barrier_func+0x250/0x250
>> [ 145.908013] [<ffffffff810abc03>] ?
>> trace_hardirqs_on_caller+0xf3/0x240
>> [ 145.908013] [<ffffffff810d9afa>] rcu_do_batch+0x2ea/0x6b0
>
> yes. full bpf test still crashes.
> That's why I said trace.patch is passing ;)
> There is something else in there. One 'fix' at a time.
Ah, sorry, I read it is working now :) Anyway, I'll keep looking
as well.
Yesterday I wrote a small torture program for the map
implementation. Just to rule out memory corruption there.
Are you interested in it? If yes I could clean it a bit.
It is based on Paul's rcu torturing (Finally I can write
this word without a typo :))
Here a rough/dirty version:
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/bpf.h>
#include <linux/torture.h>
#include <linux/slab.h>
struct bpf_test {
struct bpf_map *map;
const struct bpf_map_ops *ops;
};
static struct bpf_test test;
static struct task_struct **torture_reads;
static struct task_struct **torture_writes;
torture_param(int, nreads, -1, "Number of BPF torture threads");
torture_param(int, nwrites, -1, "Number of BPF torture threads");
torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");
torture_param(int, onoff_interval, 0, "Time between CPU hotplugs (s), 0=disable");
torture_param(int, shutdown_secs, 0, "Shutdown time (s), <= zero to disable.");
torture_param(int, stutter, 5, "Number of seconds to run/halt test");
torture_param(bool, verbose, true,
"Enable verbose debugging printk()s");
static int nrealreads;
static int nrealwrites;
static int torture_runnable = 1;
module_param(torture_runnable, int, 0444);
MODULE_PARM_DESC(torture_runnable, "Start rcutorture at boot");
static char *torture_type = "bpf";
module_param(torture_type, charp, 0444);
MODULE_PARM_DESC(torture_type, "Type of BPF to torture ( ...)");
static int bpf_torture_writes(void *arg)
{
int i, v;
do {
v = 1234;
rcu_read_lock();
for (i = 0; i < 1000; i++) {
test.ops->map_update_elem(test.map, &v, &v, BPF_ANY);
v = next_pseudo_random32(v);
}
rcu_read_unlock();
stutter_wait("bpf_torture_write");
} while (!torture_must_stop());
torture_kthread_stopping("bpf_torture_write");
return 0;
}
static int bpf_torture_reads(void *arg)
{
int *r;
int key, next_key;
do {
key = -1;
rcu_read_lock();
while (test.ops->map_get_next_key(test.map, &key, &next_key) == 0) {
r = test.ops->map_lookup_elem(test.map, &next_key);
test.ops->map_delete_elem(test.map, &next_key);
key = next_key;
}
rcu_read_unlock();
stutter_wait("bpf_torture_read");
} while (!torture_must_stop());
torture_kthread_stopping("bpf_torture_read");
return 0;
}
static void bpf_torture_cleanup(void)
{
int i;
torture_cleanup_begin();
if (torture_reads) {
for (i = 0; i < nrealreads; i++)
torture_stop_kthread(rcu_torture_reads,
torture_reads[i]);
kfree(torture_reads);
}
if (torture_writes) {
for (i = 0; i < nrealwrites; i++)
torture_stop_kthread(rcu_torture_writes,
torture_writes[i]);
kfree(torture_writes);
}
if (!test.map) {
test.ops->map_free(test.map);
test.map = NULL;
}
torture_cleanup_end();
}
static int __init bpf_torture_init(void)
{
union bpf_attr attr;
int i, err;
if (nreads >= 0) {
nrealreads = nreads;
} else {
nrealreads = num_online_cpus() - 1;
if (nrealreads <= 0)
nrealreads = 1;
}
if (nwrites >= 0) {
nrealwrites = nwrites;
} else {
nrealwrites = num_online_cpus() - 1;
if (nrealwrites <= 0)
nrealwrites = 1;
}
if (!torture_init_begin(torture_type, verbose, &torture_runnable))
return -EBUSY;
torture_reads = kzalloc(nrealreads * sizeof(torture_reads[0]), GFP_KERNEL);
if (!torture_reads)
return -ENOMEM;
torture_writes = kzalloc(nrealwrites * sizeof(torture_writes[0]), GFP_KERNEL);
if (!torture_writes)
return -ENOMEM;
attr.map_type = BPF_MAP_TYPE_HASH;
attr.key_size = sizeof(u32);
attr.value_size = sizeof(u32);
attr.max_entries = 1000;
test.ops = bpf_get_map_ops(attr.map_type);
if (!test.ops)
return -ENOENT;
test.map = test.ops->map_alloc(&attr);
if (IS_ERR(test.map))
return PTR_ERR(test.map);
err = torture_stutter_init(stutter * HZ);
if (err)
return err;
for (i = 0; i < nrealreads; i++) {
err = torture_create_kthread(bpf_torture_reads,
NULL, torture_reads[i]);
if (err)
return err;
}
for (i = 0; i < nrealwrites; i++) {
err = torture_create_kthread(bpf_torture_writes,
NULL, torture_writes[i]);
if (err)
return err;
}
err = torture_shutdown_init(shutdown_secs, bpf_torture_cleanup);
if (err)
return err;
err = torture_onoff_init(onoff_holdoff * HZ, onoff_interval * HZ);
if (err)
return err;
torture_init_end();
return 0;
}
module_init(bpf_torture_init);
module_exit(bpf_torture_cleanup);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Daniel Wagner <daniel.wagner@xxxxxxxxxxxx>");
MODULE_DESCRIPTION("BPF torture tests");
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/