container_of没有返回预期的地址

时间:2015-07-21 21:25:42

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

我不确定我做错了什么,但现在是时候睁大眼睛了。我创建了一个device_create()设备提供了一些"额外数据"如下:

    pDevice = device_create(ahcip_class, NULL, /*no parent*/
            MKDEV(AHCIP_MAJOR, AHCIP_MINOR + i), &mydevs[i],
            DRIVER_NAME "%d", AHCIP_MINOR + i);

期望我的sysfs属性函数将指向struct kobject的{​​{1}}成员我使用属性函数执行以下操作

struct device

上述函数的输出(浓缩)显示:

static ahcip_dev *get_ahcip_dev(struct kobject *ko)
{
    ahcip_dev *adev = NULL;
    struct device *pdev = container_of(ko, struct device, kobj);
    if (!pdev) {
        pr_err("%s:%d unable to find device struct in kobject\n",
                __func__, __LINE__);
        return NULL;
    }

    /* some debugging stuff */
     pr_info("%s:%d mydevs[0] %p\n", __func__, __LINE__, mydevs);
    pr_info("%s:%d mydevs[1] %p\n", __func__, __LINE__, mydevs+1);
    pr_info("%s:%d mydevs[0].psysfs_dev %p\n", __func__, __LINE__,
            mydevs->psysfs_dev);
    pr_info("%s:%d mydevs[1].psysfs_dev %p\n", __func__, __LINE__,
            (mydevs + 1)->psysfs_dev);
    pr_info("%s:%d pdev %p\n", __func__, __LINE__, pdev);
    adev = (ahcip_dev*)dev_get_drvdata(pdev);

    /* return the pointer anyway, but if it's null, print to klog */
    if (!adev)
        pr_err("%s:%d no ahcip_dev, private driver data is NULL\n",
                __func__, __LINE__);

    return adev;
}

static ssize_t pxis_show(struct kobject *kobj, struct kobj_attribute *attr,
        char *buff)
{
    u32 pi = 0;
    ahcip_dev *adev = get_ahcip_dev(kobj);

    /* get_ahcip_dev() will print what happened, this needs to return
     * error code
     */
    if (!adev)
        return -EIO;

    pi = adev->port_index;

    return sprintf(buff, "%08x\n", get_port_reg(adev->hba->ports[pi], 0x10));
}
在这种情况下,

pdev应指向与mydevs [1] .psysfs_dev相同的内存位置,但它的16个字节"更早的"。我做错了什么?

2 个答案:

答案 0 :(得分:0)

我不想回答我自己的问题,但在这种情况下这似乎是合适的。问题的根源是对属性函数需要处理的错误假设。属性函数具有此原型you can view in context here

ssize_t (*show)(struct kobject *, struct attribute *,char *);
ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t);

由于device_create()函数返回如下定义的struct device对象(excerpt only, see full def here

struct device {
    struct device           *parent;

    struct device_private   *p;

    struct kobject kobj;
    ...
}

我认为我的属性函数必须处理这个指针。通过对问题描述的阅读表明,当我使用container_of宏来获取我认为包含struct device的地址时,我早到16个字节。请注意,此结构的前两个字段是指针。在我的64位系统上,这是16个字节。

因为函数原型定义如上所示,我假设我得到了对kobj字段的引用。相反,我得到了实际的struct device对象。换句话说,我在功能输入时获得了我想要的地址,并且仍在尝试找到它。

关于这方面的一些内容可以在Linux内核文档的迷宫中记录。如果有人知道,请在此处输入链接。我读了很多,但没有看到这一个来。我希望这个问题和答案有助于其他一些内核新手。

答案 1 :(得分:0)

您的示例未显示您是如何创建sysfs属性的,也未显示您的pxis_show()函数与其关联的方式。由于您尝试将此属性连接到struct device,您是否可能正在调用device_create_file()来创建sysfs节点?如果是这样,检查struct device_attribute的回调原型可能更有意义。您将看到show / store回调看起来像:

ssize_t (*show)(struct device *dev, struct device_attribute *attr, char *buf);
ssize_t (*store)(struct device *dev, struct device_attribute *attr,
                 const char *buf, size_t count);

在哪种情况下可以更好地解释您的额外偏移问题 - 第一个参数实际上已经指向您的struct device,而不是嵌入式kobj成员,因此执行container_of()将再带回16个字节。

您可能会将device_attribute回调与struct sysfs_ops格式混淆,因为它们看起来相似,但请注意参数类型不同。事实上,从sysfs_opsstruct device_attribute的映射可以通过包装函数dev_attr_showdev_attr_store看到,可以找到here