for_each_online_cpu获取指向cpuinfo_x86的指针

时间:2015-03-16 12:02:49

标签: c linux linux-kernel linux-device-driver cpu

linux内核中的 cpuinfo 模块使用此代码获取指向cpu的指针:

ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    // (...)
    struct seq_file *m = file->private_data;
    void *p;
    // (...)
    p = m->op->start(m, &pos);

在proc.c:

中可以找到 start 方法
static void *c_start(struct seq_file *m, loff_t *pos)
{
    *pos = cpumask_next(*pos - 1, cpu_online_mask);
    if ((*pos) < nr_cpu_ids)
        return &cpu_data(*pos);
    return NULL;
}

从中返回指向void*的指针后,接下来将其传递给 show 方法:

err = m->op->show(m, p);

将指针指定为指向 cpuinfo_x86 的指针:

static int show_cpuinfo(struct seq_file *m, void *v)
{
    struct cpuinfo_x86 *c = v;
    unsigned int cpu;
    int i;

    cpu = c->cpu_index;

但是,如果我在我的代码(linux内核模块)中做了类似的事情:

    get_online_cpus();
    pos = kmalloc( sizeof( loff_t), GFP_KERNEL);
    *pos = 0;
    *pos = cpumask_next(*pos - 1, cpu_online_mask);
    if ( (*pos) < nr_cpu_ids)
    {
         c = &cpu_data(*pos);
         cpu = c->cpu_index;  // SIGSEGV !
    }

指针不正确(指向可能是有效地址的内容,但我无法访问它指向的内容)。如果我使用for_each_online_cpu宏,则会发生同样的事情:

for_each_online_cpu( cpuid)
{
    c = &cpu_data(cpuid);

为什么我会得到SIGSEGV?我知道 vfs 传递给 cpuinfo 的文件是特殊的顺序文件,但它似乎与cpu_data宏无关。截至目前,我可以看到的唯一区别是,在第一种情况下,指针被传递给函数,然后在该函数内部分配,因此我们有一个堆栈框架等。这与优化有关吗?

如果我在单独的功能中进行分配,它可以工作:

static void*
mpsrv_get_cpu_ptr( loff_t *pos)
{
    *pos = cpumask_next(*pos - 1, cpu_possible_mask);

    if ( (*pos) < nr_cpu_ids)
        return &cpu_data(*pos);

    return NULL;
}

static void 
mpsrv_stat_cpu( struct mpsrv_cpu_info *cpu_info, void *v)
{
    struct cpuinfo_x86 *c = v;  // OK
    unsigned int cpu;

    cpu = c->cpu_index;         // OK
    // (...)
}

// code

    get_online_cpus();
    pos = cpu_n = 0;

    while ( ( p = mpsrv_get_cpu_ptr( &pos)))
    {
        mpsrv_stat_cpu( cpu_info, p);

        ++cpu_n;
        ++pos;
    }

    put_online_cpus(); 

cpuinfo.c 中的内核代码还返回一个指向 cpuinfo_x86 的指针,该指针是在单独的函数 c_start()中获得的。 如果需要一些其他信息,请告诉我。谢谢。

0 个答案:

没有答案