简体   繁体   中英

Linux Kernel Not Passing Complete Structure to sysfs Callback

I am reasonably new to sysfs with respect to driver development and I seem to be observing some rather odd behavior. To make a long story short, it seems that the kernel is not passing back complete structs to my callback. This driver is a rather simple SPI-ADC driver that is being used to read analog thermal / voltage data.

Now, I have a hard time believing that I just found a bug in the Linux kernel in such a widely-used subsystem. I have scoured the internet for anything that might help, but all signs indicate that this should work as is. Other passed structures seem to be populated correctly, it is only the attr->attr member that appears to be NULL .

I should also mention that this is against the 3.2 kernel.

So, in short, what would causes sysfs callbacks to not receive a fully populated kobj_attribute struct?

Sample Code:

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 ...

Output Produced:

[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

References

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/


Edit 1:

To summarize the comments below, I manually called sysfs_create_group from my _init and the kobj_attribute struct passed to the callback appeared to be correctly populated. The callback now works without issue (or modification, for that matter). As was stated below, spi_register_driver just calls sysfs_create_group . So, why would one invoke the callback properly while the other does not?

Per comments below, below is the complete _init function and spi_driver structure. The test that I did to manually create the paths myself was based off the _init code in the first reference with almost no modification.

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);

The .groups member of struct device_driver must point to a NULL-terminated list of pointers to attribute groups, not to a single pointer to an attribute group. So, instead of attr_group_ptr , you need:

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

...and then

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

However, there's a helper macro to declare both the attribute group and list of attribute groups that you can use instead:

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,
    },

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM