当变量在结构中的结构中时如何使用 container_of()?
How to use container_of() when the variable is in a struct within a struct?
我浏览了很多关于 container_of()
的问题,但没有找到询问如何使用 container_of()
在结构中检索结构的问题。如果这个问题重复,请指出。抱歉给您带来不便。
我目前正在实现一个 PCI 设备驱动程序 remove() 函数结合另一个内核模块,具有以下设置(我删除了一些其他字段以使这个问题易于阅读):
struct my_device {
struct mutex lock;
struct my_dev {
struct cdev cdev;
} my_dev;
struct pci {
struct cdev cdev;
struct pci_dev *pdev;
} pci;
};
问题来了:当我们在struct pci_dev *
类型的struct pci中有一个指向pdev的指针时,我们如何得到struct pci
,然后得到struct my_device
? 请注意,在 probe(struct pci_dev *dev, const struct pci_device_id *id)
中,我已将 dev
分配给先前分配的 struct my_device *dev_ptr
,即 dev_ptr->pci.pdev = dev;
我尝试了以下方法:
struct pci *pci_t;
pci_t = container_of(ptr, struct pci, pdev)
但这没有用。
报错信息如下:
error: call to '__compiletime_assert_243' declared with attribute error: pointer type mismatch in container_of()
如有任何想法,我们将不胜感激。
更新:
我尝试了评论中的方法。由于pci驱动的remove()函数有一个参数——struct pci_dev *dev
,代表对应的pci设备,所以我做了如下操作:
struct my_device *mydev;
mydev = container_of(&dev, struct my_device, pci.pdev);
但是它没有return指向正确结构的指针mydev
。
这是 container_of()
宏的简化定义:
#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
offsetof(type, member)
宏如 C 标准中所述,给出了从某些结构类型 type
开始到该类型某些成员开始 member
的字节数]. ptr
应该 与指向成员类型的指针兼容(但上面的简化版本不关心)。 (char *)(ptr)
将指针转换为指向成员的字节指针,以便指针减法 (char *)(ptr) - offsetof(type, member)
生成指向包含结构类型开头的字节指针。最后,强制转换 (type *)
将该指针转换为正确的类型。
用法示例。鉴于:
struct my_device {
struct mutex lock;
struct my_dev {
struct cdev cdev;
} my_dev;
struct pci {
struct cdev cdev;
struct pci_dev *pdev;
} pci;
};
和指向已分配 struct my_device
:
的指针
struct my_device *mydev = kzalloc(sizeof(*mydev), GFP_KERNEL);
和指向 pci.pdev
成员的指针:
struct pci_dev **ppdev = &mydev->pci.pdev;
然后可以使用 container_of()
:
将其转换回指向包含 struct my_device
的指针
struct my_device *myd = container_of(ppdev, struct my_device, pci.pdev);
OP 有这样的内容:
struct my_device *mydev = kzalloc(sizeof(*mydev), GFP_KERNEL);
mydev->pci.pdev = pcidev;
并试图从指针 pcidev
返回到 struct my_device
,如下所示:
struct my_device *mydev = container_of(&pcidev, struct my_device, pci.pdev); /* wrong! */
这不起作用,因为 &pcidev
是 pcidev
变量的地址,而不是原始 mydev->pci.pdev
成员的地址。
Linux 内核允许 PCI 设备驱动程序将任意 void *
值与 PCI 设备相关联。这通常在 PCI 设备驱动程序的 probe()
处理程序中完成,如下所示:
pci_set_drvdata(pcidev, mydev);
然后直到 PCI 设备从驱动程序中删除,或者驱动程序使用其他值调用 pci_set_drvdata
,可以通过调用 pci_get_drvdata()
:
来检索指针
struct my_device *mydev = pci_get_drvdata(pcidev);
更一般地说,pci_set_drvdata()
和 pci_get_drvdata()
只是 dev_set_drvdata()
和 dev_get_drvdata()
的包装,将任意 void *
值与 [=47= 相关联]. struct pci_device
结构定义包含一个成员 struct device dev;
。 pci_set_drvdata(pcidev, ptr)
等同于dev_set_drvdata(&pcidev->dev, ptr)
,pci_get_drvdata(pcidev)
等同于dev_get_drvdata(&pcidev->dev)
.
通常,驱动程序代码有一个指向 struct device
的指针,它知道它嵌入在 struct pci_dev
中,并且它可以使用 container_of()
获取指向包含 struct pci_dev
:
/* dptr is pointing the the struct device inside a struct pci_dev. */
static void foo(struct device *dptr)
{
struct pci_dev *pcidev = container_of(dptr, struct pci_dev, dev);
/* ... */
}
如果驱动之前使用过pci_set_drvdata()
或dev_set_drvdata()
,可以使用pci_get_drvdata()
或dev_get_drvdata()
取回设定值:
static void foo(struct device *dptr)
{
struct pci_dev *pcidev = container_of(dptr, struct pci_dev, dev);
struct my_device *mydev = pci_get_drvdata(pcidev);
struct my_device *mydev1 = dev_get_drvdata(dptr);
/* (mydev == mydev1) is true */
struct pci_dev *pcidev1 = mydev->pci.pdev;
/* (pcidev == pcidev1) is true assuming mydev->pci.pdev was previously set to pcidev */
/* ... */
}
尽管它有效,但将 pci_set_drvdata()
与之前对 dev_get_drvdata()
的调用混合使用或将 pci_get_drvdata()
与之前对 dev_set_drvdata()
的调用混合使用可能是不好的风格。
我浏览了很多关于 container_of()
的问题,但没有找到询问如何使用 container_of()
在结构中检索结构的问题。如果这个问题重复,请指出。抱歉给您带来不便。
我目前正在实现一个 PCI 设备驱动程序 remove() 函数结合另一个内核模块,具有以下设置(我删除了一些其他字段以使这个问题易于阅读):
struct my_device {
struct mutex lock;
struct my_dev {
struct cdev cdev;
} my_dev;
struct pci {
struct cdev cdev;
struct pci_dev *pdev;
} pci;
};
问题来了:当我们在struct pci_dev *
类型的struct pci中有一个指向pdev的指针时,我们如何得到struct pci
,然后得到struct my_device
? 请注意,在 probe(struct pci_dev *dev, const struct pci_device_id *id)
中,我已将 dev
分配给先前分配的 struct my_device *dev_ptr
,即 dev_ptr->pci.pdev = dev;
我尝试了以下方法:
struct pci *pci_t;
pci_t = container_of(ptr, struct pci, pdev)
但这没有用。
报错信息如下:
error: call to '__compiletime_assert_243' declared with attribute error: pointer type mismatch in container_of()
如有任何想法,我们将不胜感激。
更新:
我尝试了评论中的方法。由于pci驱动的remove()函数有一个参数——struct pci_dev *dev
,代表对应的pci设备,所以我做了如下操作:
struct my_device *mydev;
mydev = container_of(&dev, struct my_device, pci.pdev);
但是它没有return指向正确结构的指针mydev
。
这是 container_of()
宏的简化定义:
#define container_of(ptr, type, member) ((type *)((char *)(ptr) - offsetof(type, member)))
offsetof(type, member)
宏如 C 标准中所述,给出了从某些结构类型 type
开始到该类型某些成员开始 member
的字节数]. ptr
应该 与指向成员类型的指针兼容(但上面的简化版本不关心)。 (char *)(ptr)
将指针转换为指向成员的字节指针,以便指针减法 (char *)(ptr) - offsetof(type, member)
生成指向包含结构类型开头的字节指针。最后,强制转换 (type *)
将该指针转换为正确的类型。
用法示例。鉴于:
struct my_device {
struct mutex lock;
struct my_dev {
struct cdev cdev;
} my_dev;
struct pci {
struct cdev cdev;
struct pci_dev *pdev;
} pci;
};
和指向已分配 struct my_device
:
struct my_device *mydev = kzalloc(sizeof(*mydev), GFP_KERNEL);
和指向 pci.pdev
成员的指针:
struct pci_dev **ppdev = &mydev->pci.pdev;
然后可以使用 container_of()
:
struct my_device
的指针
struct my_device *myd = container_of(ppdev, struct my_device, pci.pdev);
OP 有这样的内容:
struct my_device *mydev = kzalloc(sizeof(*mydev), GFP_KERNEL);
mydev->pci.pdev = pcidev;
并试图从指针 pcidev
返回到 struct my_device
,如下所示:
struct my_device *mydev = container_of(&pcidev, struct my_device, pci.pdev); /* wrong! */
这不起作用,因为 &pcidev
是 pcidev
变量的地址,而不是原始 mydev->pci.pdev
成员的地址。
Linux 内核允许 PCI 设备驱动程序将任意 void *
值与 PCI 设备相关联。这通常在 PCI 设备驱动程序的 probe()
处理程序中完成,如下所示:
pci_set_drvdata(pcidev, mydev);
然后直到 PCI 设备从驱动程序中删除,或者驱动程序使用其他值调用 pci_set_drvdata
,可以通过调用 pci_get_drvdata()
:
struct my_device *mydev = pci_get_drvdata(pcidev);
更一般地说,pci_set_drvdata()
和 pci_get_drvdata()
只是 dev_set_drvdata()
和 dev_get_drvdata()
的包装,将任意 void *
值与 [=47= 相关联]. struct pci_device
结构定义包含一个成员 struct device dev;
。 pci_set_drvdata(pcidev, ptr)
等同于dev_set_drvdata(&pcidev->dev, ptr)
,pci_get_drvdata(pcidev)
等同于dev_get_drvdata(&pcidev->dev)
.
通常,驱动程序代码有一个指向 struct device
的指针,它知道它嵌入在 struct pci_dev
中,并且它可以使用 container_of()
获取指向包含 struct pci_dev
:
/* dptr is pointing the the struct device inside a struct pci_dev. */
static void foo(struct device *dptr)
{
struct pci_dev *pcidev = container_of(dptr, struct pci_dev, dev);
/* ... */
}
如果驱动之前使用过pci_set_drvdata()
或dev_set_drvdata()
,可以使用pci_get_drvdata()
或dev_get_drvdata()
取回设定值:
static void foo(struct device *dptr)
{
struct pci_dev *pcidev = container_of(dptr, struct pci_dev, dev);
struct my_device *mydev = pci_get_drvdata(pcidev);
struct my_device *mydev1 = dev_get_drvdata(dptr);
/* (mydev == mydev1) is true */
struct pci_dev *pcidev1 = mydev->pci.pdev;
/* (pcidev == pcidev1) is true assuming mydev->pci.pdev was previously set to pcidev */
/* ... */
}
尽管它有效,但将 pci_set_drvdata()
与之前对 dev_get_drvdata()
的调用混合使用或将 pci_get_drvdata()
与之前对 dev_set_drvdata()
的调用混合使用可能是不好的风格。