编辑#4:
我想通了,我不应该被分配attr_groups
到groups
该领域driver
中的场struct platform_driver
结构。寻找/* WRONGO: should not be assigned here. */
下面的评论。
我还没想好我应该把它分配在哪里......
由于 NULL 引用,我的平台驱动程序代码在读取 sysfs 属性时设法导致内核“OOPS”。我确定这是以下代码中的一个简单疏忽,但我看不到它:
...
static int samples_per_frame = SAMPLE_CHANNEL_COUNT;
DEVICE_INT_ATTR(samples_per_frame, S_IRUGO | S_IWUSR, samples_per_frame);
static struct attribute *attrs[] = {
&dev_attr_samples_per_frame.attr.attr, NULL,
};
static struct attribute_group attr_group = {
.attrs = attrs,
};
static const struct attribute_group *attr_groups[] = {
&attr_group, NULL,
};
static struct platform_driver platform = {
.remove = my_remove,
.probe = my_probe,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.groups = attr_groups, /* WRONGO: should not be assigned here. */
.of_match_table = of_match,
},
};
...
Run Code Online (Sandbox Code Playgroud)
其中,编译干净(Linux 3.12),当模块加载时,安装和探测运行顺利,属性出现在 sysfs 中,但是当我尝试读取它时,内核“oops”随之而来。
/sys/bus/platform/drivers/my_driver# ls
ff250000.my_driver samples_per_frame uevent
/sys/bus/platform/drivers/my_driver#
/sys/bus/platform/drivers/my_driver# cat samples_per_frame
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = bf1e0000
[00000000] *pgd=3f1d8831, *pte=00000000, *ppte=00000000
Internal error: Oops: 17 [#1] SMP ARM
Modules linked in: my_driver(O)
CPU: 1 PID: 194 Comm: cat Tainted: G O 3.12.0 #6
task: bf054000 ti: bf194000 task.ti: bf194000
PC is at device_show_int+0x2c/0x38
LR is at drv_attr_show+0x2c/0x38
pc : [<80308f58>] lr : [<8030b6fc>] psr: a0000013
sp : bf195ee8 ip : 00000d58 fp : bf195ef4
r10: bf1d1380 r9 : 7e946c20 r8 : bf195f78
r7 : bf1d13d8 r6 : bf1d13c0 r5 : bfbc9e00 r4 : 8055d520
r3 : 00000000 r2 : 80620d58 r1 : 00001000 r0 : bf190000
Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
Control: 10c5387d Table: 3f1e004a DAC: 00000015
Process cat (pid: 194, stack limit = 0xbf194248)
Stack: (0xbf195ee8 to 0xbf196000)
5ee0: bf195f04 bf195ef8 8030b6fc 80308f38 bf195f44 bf195f08
5f00: 80166118 8030b6dc 8076ed30 bf14b000 bfbd8d80 00001000 bfbd8d88 bfbd8d80
5f20: 00001000 7e946c20 bf195f78 00000000 bf194000 00001000 bf195f74 bf195f48
5f40: 8010722c 80166084 801061e4 801118c0 00000000 00000000 bfbd8d80 7e946c20
5f60: 00000000 00001000 bf195fa4 bf195f78 8010741c 80107190 00000000 00000000
5f80: 00001000 7e946c20 00000003 00000003 8000ec88 00000000 00000000 bf195fa8
5fa0: 8000ea40 801073dc 00001000 7e946c20 00000003 7e946c20 00001000 00000000
5fc0: 00001000 7e946c20 00000003 00000003 00000001 00000001 00000001 00000003
5fe0: 00000000 7e946bfc 0001079d 76f5e1cc 40000010 00000003 00000000 00000000
[<80308f58>] (device_show_int+0x2c/0x38) from [<8030b6fc>] (drv_attr_show+0x2c/0x38)
[<8030b6fc>] (drv_attr_show+0x2c/0x38) from [<80166118>] (sysfs_read_file+0xa0/0x144)
[<80166118>] (sysfs_read_file+0xa0/0x144) from [<8010722c>] (vfs_read+0xa8/0x148)
[<8010722c>] (vfs_read+0xa8/0x148) from [<8010741c>] (SyS_read+0x4c/0x80)
[<8010741c>] (SyS_read+0x4c/0x80) from [<8000ea40>] (ret_fast_syscall+0x0/0x30)
Code: e5913010 e1a0200c e3a01a01 e3482062 (e5933000)
---[ end trace 5cdf9dda0d86a7db ]---
Segmentation fault
Run Code Online (Sandbox Code Playgroud)
为什么我得到一个空引用?
编辑#1:
如果我替换DEVICE_INT_ATTR()
宏DEVICE_ATTR()
并提供我自己的show()
&store()
函数,它工作正常。
编辑#2:
看来DEVICE_INT_ATTR()
宏将该var
字段设置为 NULL。嗯……
编辑#3:
当我struct dev_ext_attribute
用DEVICE_INT_ATTR()
宏创建结构时,我可以转储变量。那是; printk()
在我的探测函数中查看时,我试图在 sysfs 中公开的结构地址、函数指针和整数地址都是正确的,但是当我的自旋show()
函数查看结构时,结构处于不同的位置地址,该var
字段为 NULL。
问题是由于attr_groups
在这里分配结构而产生的:
static struct platform_driver platform = {
.remove = my_remove,
.probe = my_probe,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.groups = attr_groups, /* WRONGO: should not be assigned here. */
.of_match_table = of_match,
},
};
Run Code Online (Sandbox Code Playgroud)
通过这样做struct class
,一切都会按预期进行:
static int __init cz_tdm_init(void)
{
int ret;
pr_info("MODNAME=%s", KBUILD_MODNAME);
/* Dynamically allocate a major number and a
* range of DEV_MINOR_NUMBER_COUNT (1) minor numbers. */
if ((ret = alloc_chrdev_region(&first, 0, DEV_MINOR_NUMBER_COUNT, DRIVER_NAME)) < 0) {
ret = -ENODEV;
goto exit;
}
/* Add the char device to the system. */
cdev_init(&cdev, &fops);
if ((ret = cdev_add(&cdev, first, DEV_MINOR_NUMBER_COUNT)) < 0) {
ret = -ENODEV;
goto exit;
}
resources.cdev = 1;
/* Create a class entry in sysfs */
if ((class = class_create(THIS_MODULE, "coveloz")) == NULL) {
pr_err("Couldn't create 'struct class' structure.");
ret = -ENODEV;
goto exit;
}
class->dev_groups = attr_groups; /* RIGHTO */
/* Create the /dev/ file system entry */
/* return value ignored: there's a 'struct class' to 'struct device' mapping */
if (device_create(class, NULL, first, NULL, DRIVER_NAME) == NULL) {
pr_err("Couldn't create entry in '/dev/' file system.");
ret = -ENODEV;
goto exit;
}
Run Code Online (Sandbox Code Playgroud)