【问题标题】:Linux Kernel Not Passing Complete Structure to sysfs CallbackLinux 内核未将完整结构传递给 sysfs 回调
【发布时间】:2015-01-07 02:41:20
【问题描述】:

在驱动程序开发方面,我对 sysfs 相当陌生,而且我似乎观察到一些相当奇怪的行为。长话短说,内核似乎没有将完整的结构传递回我的回调。该驱动程序是一个相当简单的 SPI-ADC 驱动程序,用于读取模拟热/电压数据。

现在,我很难相信自己在如此广泛使用的子系统中发现了 Linux 内核中的错误。我已经在互联网上搜索了任何可能有帮助的东西,但所有迹象都表明这应该可以正常工作。其他传递的结构似乎已正确填充,只有 attr->attr 成员似乎是 NULL

我还要提一下,这是针对 3.2 内核的。

那么,简而言之,什么会导致 sysfs 回调没有收到完全填充的 kobj_attribute 结构?

示例代码:

static ssize_t ads7960_sysfs_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
{
int var, rc, i = 0, j = 0;
long channel = 0;

//DEBUG
printk("%s: kobj->name = %s\n", __func__, kobj->name);
printk("%s: attr = %p\n", __func__, attr);
printk("%s: attr->attr = %p\n", __func__, attr->attr);
printk("%s: attr->attr.name = %s\n", __func__, attr->attr.name);
printk("%s: attr->attr.mode = %o\n", __func__, attr->attr.mode);

/* check for silly things */
if ((attr->attr.name == NULL) || (strlen(attr->attr.name) < 1)) {
    printk("%s: invalid channel number. = %s\n", __func__, attr->attr.name);
    return -EINVAL;
}

... snip (We never get past here) ...

static struct kobj_attribute ads7960_ch0  = __ATTR(0,  0444, ads7960_sysfs_show, NULL);
static struct kobj_attribute ads7960_ch1  = __ATTR(1,  0444, ads7960_sysfs_show, NULL);
static struct kobj_attribute ads7960_ch2  = __ATTR(2,  0444, ads7960_sysfs_show, NULL);

... snip (there are 12 total ADC channels in the same format) ...

static struct attribute *ch_attrs[] = {
    &ads7960_ch0.attr,
    &ads7960_ch1.attr,
    &ads7960_ch2.attr,

    ... snip (same 12 channels as above)...

    NULL,
};

static struct attribute_group attr_group = {
    .attrs = ch_attrs,
};

static struct attribute_group *attr_group_ptr = &attr_group;

... snip ...

static struct spi_driver ads7960_driver = {
    .driver = {
        .name   = "ads7960",
        .bus    = &spi_bus_type,
        .owner  = THIS_MODULE,
        .groups = &attr_group_ptr,
    },
    .probe          = ads7960_probe,
    .remove         = __devexit_p(ads7960_remove),
    .id_table       = ads7960_id,
};

... snip ...

产生的输出:

[root@172.17.152.42: ]# cat /sys/bus/spi/drivers/ads7960/4
[   65.344789] ads7960_sysfs_show: kobj->name = ads7960
[   65.350026] ads7960_sysfs_show: attr = dc934000
[   65.354859] ads7960_sysfs_show: attr->attr =   (null)
[   65.360155] ads7960_sysfs_show: attr->attr.name = (null)
[   65.365746] ads7960_sysfs_show: attr->attr.mode = 0
[   65.370861] ads7960_sysfs_show: invalid channel number. = (null)
cat: read error: Invalid argument

参考文献

http://www.cs.fsu.edu/~baker/devices/lxr/http/source/linux/samples/kobject/kobject-example.c http://kroah.com/log/blog/2013/06/26/how-to-create-a-sysfs-file-correctly/


编辑 1:

总结下面的 cmets,我从 _init 手动调用了 sysfs_create_group,并且传递给回调的 kobj_attribute 结构似乎已正确填充。回调现在可以正常工作(或修改,就此而言)。如下所述,spi_register_driver 只是调用sysfs_create_group。那么,为什么一个能正确调用回调而另一个不能呢?

下面的每个 cmets,下面是完整的 _init 函数和 spi_driver 结构。我自己手动创建路径的测试是基于第一个参考中的_init 代码,几乎没有修改。

static struct spi_driver ads7960_driver = {
    .driver = {
        .name   = "ads7960",
        .bus    = &spi_bus_type,
        .owner  = THIS_MODULE,
        .groups = attr_groups,
    },
    .probe          = ads7960_probe,
    .remove         = __devexit_p(ads7960_remove),
    .id_table       = ads7960_id,
};

static int __init ads7960_init(void)
{  
    return spi_register_driver(&ads7960_driver);
}
module_init(ads7960_init);

【问题讨论】:

  • attr-&gt;attr 不是指针,而是struct,因此您不应该尝试使用%p 格式打印它(您只是看到第一个成员的值,即attr-&gt;attr.name)

标签: c linux linux-kernel driver


【解决方案1】:

struct device_driver 的成员.groups 必须指向以 NULL 结尾的属性组指针列表,而不是指向属性组的单个指针。因此,您需要:而不是 attr_group_ptr

static struct attribute_group *attr_groups[] = { &attr_group, NULL };

...然后

static struct spi_driver ads7960_driver = {
    .driver = {
        .name   = "ads7960",
        .bus    = &spi_bus_type,
        .owner  = THIS_MODULE,
        .groups = attr_groups,
    },

但是,有一个帮助宏来声明属性组和属性组列表,您可以使用它们来代替:

static struct attribute *ch_attrs[] = {
    &ads7960_ch0.attr,
    &ads7960_ch1.attr,
    &ads7960_ch2.attr,

    /* ... */

    NULL,
};

ATTRIBUTE_GROUPS(ch);  /* declares ch_group and ch_groups */

static struct spi_driver ads7960_driver = {
    .driver = {
        .name   = "ads7960",
        .bus    = &spi_bus_type,
        .owner  = THIS_MODULE,
        .groups = ch_groups,
    },

【讨论】:

  • 我按照您上面的概述更新了我的代码,以包含一个NULL-终止的attribute_group* 数组。不幸的是,我看到了同样的行为。 Thins 给我带来了一个额外的问题:如果结构以某种方式格式不正确,sysfs 是如何创建所有 12 个属性节点的?此外,内核是否只是将我传入的结构传回,还是在 init 和回调之间进行了某种程度的转换?最后,我的内核源代码中似乎没有看到ATTRIBUTE_GROUPS 的定义;是在后来的内核中添加的吗?
  • @phobos51594 看起来宏 ATTRIBUTE_GROUPS 已添加到 3.11 内核 (lxr.free-electrons.com/source/include/linux/sysfs.h?v=3.11#L105) 中。您可能必须为 3.2 内核手动声明这些结构。
  • 情节变厚:如果我在驱动程序初始化中使用sysfs_create_group 创建组,则结构会正确填充,并且回调可以顺利工作。我假设内核在自动创建这些属性时只是在后台使用sysfs_create_group。自动生成属性与手动创建属性时,属性信息的存储方式是否不同?
  • @phobos51594:它确实在后台使用sysfs_create_group() - spi_register_driver() 调用driver_register(),它调用driver_add_groups(),它调用sysfs_create_group()。您可以编辑问题以显示您的驱动程序初始化函数吗?
  • @phobos51594:当您手动创建kobj 时,您使用的是哪个@?
猜你喜欢
  • 2011-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-07-18
相关资源
最近更新 更多