Linux内核模块:在信号量上调用导致NULL指针解除
我正在尝试学习Linux内核模块开发,并遵循“ Linux设备驱动程序,第三版”。我正在尝试实现仅内存的设备,例如SCULL,用打开和关闭设备,
和Close> Close
在用户空间中工作正常,但是我的阅读和<代码>写入
实现不起作用。在首次加载模块时初始化新设备的函数中,我创建了这样的信号:
// ...
struct semaphore *sema;
sema = kmalloc(sizeof(struct semaphore), GFP_KERNEL);
sema_init(sema, 1);
my_device->sem = *sema;
my_device
是包含cdev
struct and struct and其他内容的设备结构。
在我的写入
实现中,我的
ssize_t my_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) {
// ...
struct MyDev *dev = filp->private_data; // MyDev is the struct initialized above
if (down_interruptible(&dev->sem))
{
printk(KERN_ALERT "Failed to get semaphore\n");
return -ERESTARTSYS;
}
部分正常工作,就像将数据写入设备一样。 致电时
up(&dev->sem);
但是,当我在末尾
,我会得到无法在虚拟地址处理内核NULL指针删除0000000000000007A4
。内核“ oops”是内部错误:oops:96000004 [#1]
,跟踪是:
Call trace:
__raw_spin_lock_irqsave+0x3c/0xa0
try_to_wake_up+0x50/0x674
wake_up_process+0x24/0x30
__up.isra.0+0x58/0x70
up+0x68/0x70
my_write+0x250/0x2dc [devices] // my function
vfs_write+0xfc/0x2c0
ksys_write+0x74/0x100
__arm64_sys_write+0x28/0x34
invoke_syscall+0x50/0x120
el0_svc_common+0x48/0x100
do_el0_svc+0x34/0xa0
el0_svc+0x2c/0x54
el0t_64_sync_handler+0xe8/0xf0
el0t_64_sync+0x198/0x19c
Code: aa1303e0 52800001 52800022 2a0103e3 (88e37e62)
如果是相关的,则我的file> file_operations
struct struct struct看起来
static struct file_operations my_ops = {
.owner = THIS_MODULE,
.open = my_open,
.release = my_close,
.read = my_read,
.write = my_write,
};
可能是内核在我尚未定义的那个结构上寻找其他功能吗?我已经记录了my_write
中使用的所有指针,我知道它们不是零。为什么down_interible
工作但up
不起作用?
编辑:我还尝试了down
,而不是down_interible
- down
也有效,但是up
仍然不行。
仅出于完整性,这是整个my_write
ssize_t my_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
struct MyDev *dev = filp->private_data;
struct MySet *dptr;
int quantum = dev->quantum;
int qset = dev->qset;
int itemsize = quantum * qset;
int item, s_pos, q_pos, rest;
ssize_t retval = -ENOMEM;
printk(KERN_ALERT "about to get semaphore dev->sem %p\n", &dev->sem);
if (down_interruptible(&dev->sem))
{
printk(KERN_ALERT "Failed to get semaphore\n");
return -ERESTARTSYS;
}
printk(KERN_ALERT "got past semaphore\n");
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum;
q_pos = rest % quantum;
dptr = my_follow(dev, item);
printk(KERN_ALERT "after follow, dptr: %p\b", dptr);
if (dptr == NULL)
goto out;
if (!dptr->data)
{
dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
if (!dptr->data)
goto out;
memset(dptr->data, 0, qset * sizeof(char *));
printk(KERN_ALERT "zeroed dptr->data\n");
}
if (!dptr->data[s_pos])
{
dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
printk(KERN_ALERT "allocated mem for dptr->data[%d]\n", s_pos);
if (!dptr->data[s_pos])
goto out;
}
if (count > quantum - q_pos)
count = quantum - q_pos;
if (copy_from_user(dptr->data[s_pos] + q_pos, buf, count))
{
retval = -EFAULT;
goto out;
}
printk(KERN_ALERT "copied from user\n");
*f_pos += count;
retval = count;
if (dev->size < *f_pos)
dev->size = *f_pos;
printk(KERN_ALERT "calling up...\n");
out:
up(&dev->sem);
printk(KERN_ALERT "called up, returning %zx\n", retval);
return retval;
}
I'm trying to learn Linux kernel module development, and following the book "Linux Device Drivers, Third Edition". I'm trying to implement a memory-only device like scull, opening and closing the device with open
and close
in userspace works fine, but my read
and write
implementations aren't working. In the function that initializes a new device when the module is first loaded, I create the semaphore like this:
// ...
struct semaphore *sema;
sema = kmalloc(sizeof(struct semaphore), GFP_KERNEL);
sema_init(sema, 1);
my_device->sem = *sema;
my_device
is the device struct containing the cdev
struct and other things.
In my write
implementation, I have
ssize_t my_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) {
// ...
struct MyDev *dev = filp->private_data; // MyDev is the struct initialized above
if (down_interruptible(&dev->sem))
{
printk(KERN_ALERT "Failed to get semaphore\n");
return -ERESTARTSYS;
}
That part works fine, as does writing data to the device. But when I call
up(&dev->sem);
at the end, I get Unable to handle kernel NULL pointer dereference at virtual address 00000000000007a4
.
The kernel "oops" is Internal error: Oops: 96000004 [#1]
and the trace is:
Call trace:
__raw_spin_lock_irqsave+0x3c/0xa0
try_to_wake_up+0x50/0x674
wake_up_process+0x24/0x30
__up.isra.0+0x58/0x70
up+0x68/0x70
my_write+0x250/0x2dc [devices] // my function
vfs_write+0xfc/0x2c0
ksys_write+0x74/0x100
__arm64_sys_write+0x28/0x34
invoke_syscall+0x50/0x120
el0_svc_common+0x48/0x100
do_el0_svc+0x34/0xa0
el0_svc+0x2c/0x54
el0t_64_sync_handler+0xe8/0xf0
el0t_64_sync+0x198/0x19c
Code: aa1303e0 52800001 52800022 2a0103e3 (88e37e62)
If it's relevant, my file_operations
struct looks like this
static struct file_operations my_ops = {
.owner = THIS_MODULE,
.open = my_open,
.release = my_close,
.read = my_read,
.write = my_write,
};
Is it possible the kernel is looking for other functions on that struct that I haven't defined yet? I have logged out all the pointers used in my_write
and I know they're not null. Why does down_interruptible
work but not up
?
Edit: I also tried just down
instead of down_interruptible
- down
also works, but up
still doesn't.
And just for completeness, here is the entire my_write
ssize_t my_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
struct MyDev *dev = filp->private_data;
struct MySet *dptr;
int quantum = dev->quantum;
int qset = dev->qset;
int itemsize = quantum * qset;
int item, s_pos, q_pos, rest;
ssize_t retval = -ENOMEM;
printk(KERN_ALERT "about to get semaphore dev->sem %p\n", &dev->sem);
if (down_interruptible(&dev->sem))
{
printk(KERN_ALERT "Failed to get semaphore\n");
return -ERESTARTSYS;
}
printk(KERN_ALERT "got past semaphore\n");
item = (long)*f_pos / itemsize;
rest = (long)*f_pos % itemsize;
s_pos = rest / quantum;
q_pos = rest % quantum;
dptr = my_follow(dev, item);
printk(KERN_ALERT "after follow, dptr: %p\b", dptr);
if (dptr == NULL)
goto out;
if (!dptr->data)
{
dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL);
if (!dptr->data)
goto out;
memset(dptr->data, 0, qset * sizeof(char *));
printk(KERN_ALERT "zeroed dptr->data\n");
}
if (!dptr->data[s_pos])
{
dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
printk(KERN_ALERT "allocated mem for dptr->data[%d]\n", s_pos);
if (!dptr->data[s_pos])
goto out;
}
if (count > quantum - q_pos)
count = quantum - q_pos;
if (copy_from_user(dptr->data[s_pos] + q_pos, buf, count))
{
retval = -EFAULT;
goto out;
}
printk(KERN_ALERT "copied from user\n");
*f_pos += count;
retval = count;
if (dev->size < *f_pos)
dev->size = *f_pos;
printk(KERN_ALERT "calling up...\n");
out:
up(&dev->sem);
printk(KERN_ALERT "called up, returning %zx\n", retval);
return retval;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论