简单字符驱动程序崩溃

问题描述:

我正在制作一个简单的字符驱动程序,它假定写入到我的字符设备“/ dev/coffee_bean”中,读取时应显示字符串“Hi There!”。在控制台。我通过“cat/dev/coffee_bean”从设备读取,而是我的系统崩溃并重置。贝娄是我的源代码。感谢帮助。简单字符驱动程序崩溃

#include <linux/kernel.h> 
#include <linux/module.h> 
#include <linux/fs.h> 
#include <linux/cdev.h> 
#include <linux/kdev_t.h> 
#include <linux/types.h> 
#include <linux/completion.h> 
#include <linux/slab.h> 
#include <asm/uaccess.h> 
#include <linux/semaphore.h> 
MODULE_LICENSE("Dual BSD/GPL"); 

#define DEVICE_NAME "coffee_grinds" 
#define COUNT 4 
#define FIRST_MINOR 0 
#define CONST_QUANTUM 4000 
#define CONST_QSET 4000 

int test; 

module_param(test, int, S_IRUGO); 

struct my_char_structure{ 
    struct cdev my_cdev; 
    struct semaphore sem; 
    unsigned int access_key; 
    unsigned long size; 
}; 

static dev_t dev_num; 

int dev_open(struct inode *in_node, struct file *filp){ 
    struct my_char_structure *my_dev; 

    my_dev = container_of(in_node->i_cdev, struct my_char_structure, my_cdev); 
    filp->private_data = my_dev; 
    return 0; 
} 

int dev_release(struct inode *inode, struct file *filp){ 
    return 0; 
} 

ssize_t dev_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp){ 
    struct my_char_structure *my_dev = filp->private_data; 
    ssize_t retval = -ENOMEM; /* value used in "goto out" statements */ 
    char *my_string; 
    int counting; 
    printk(KERN_ALERT "Write was accessed, Lol"); 
    if (down_interruptible(&my_dev->sem)) 
     return -ERESTARTSYS; 
    my_string = kmalloc(count,GFP_KERNEL); 
    counting = copy_from_user(my_string,buff,count); 
    printk(KERN_ALERT "You wrote %s",my_string); 
    kfree(my_string); 
    up(&my_dev->sem); 

    printk(KERN_ALERT "We wrote %d bytes",counting); 
     return retval; 
    // Here is some experimental code 
} 

    ssize_t dev_read(struct file *filp, char __user *buff, size_t count, loff_t *offp){ 
     struct my_char_structure *my_dev = filp->private_data; 
     ssize_t retval = 0; 
     char *my_string; 

     printk(KERN_ALERT "Read was accessed Lol"); 

     if (down_interruptible(&my_dev->sem)) 
      return -ERESTARTSYS; 
     my_string = "Hi there!"; 
     copy_to_user(buff,my_string,10); 
     up(&my_dev->sem); 
     return retval; 

    } 

struct file_operations fops = { 
    .owner = THIS_MODULE, 
    .read = dev_read, 
    .write = dev_write, 
    .open = dev_open, 
    .release= dev_release, 
}; 

int start_mod(void){ 
    //Because we are dealing with a fictitious device, I want 
    //the driver to create my two devices with arbitrarly 
    //assigned major numbers. 
    static struct my_char_structure Dev; 
    static struct my_char_structure *my_dev = &Dev; 
    int err; 

    alloc_chrdev_region(&dev_num, FIRST_MINOR, COUNT, DEVICE_NAME); 

    sema_init(&(my_dev->sem),1); 

    cdev_init(&(my_dev->my_cdev), &fops); 
    my_dev->my_cdev.owner = THIS_MODULE; 
    my_dev->my_cdev.ops = &fops;// fops is my file operations struct 

    err = cdev_add(&my_dev->my_cdev, dev_num, COUNT); 
    if(err) 
     printk(KERN_ALERT "There was an error %d.",err); 
    printk(KERN_ALERT " insmod to major number %d",MAJOR(dev_num)); 

    return 0; 
} 

void end_mod(void){ 

    unregister_chrdev_region(dev_num, COUNT); 

} 

module_init(start_mod); 
module_exit(end_mod); 

看着你现在发布的完整代码,我没有看到任何明显的崩溃原因。你正在做的事情在其他驱动程序中完成。

只是一些观察。

有很少的错误检查。这会咬你,因为成功执行下一件事通常取决于成功执行前一件事情的先决条件。

另外,如果确实读取函数的调用没有发生崩溃,您会发现它不会产生任何内容,因为您返回0并且不会移动偏移量!大多数程序会将零回报解释为文件结束。

您必须遵守传入的缓冲区大小,否则会损坏用户空间。 cat程序可能不会执行read(fd, buf, 5);(注意,5小于您要复制到用户空间的10个字节),但可能会有一些。

顺便说一句,copy_to_usercopy_from_user是你必须测试失败也并返回-EFAULT到用户空间,告诉它在一个坏区通过调用应用程序的功能。

要调试崩溃,有两种传统方法。一个是添加更多的printk语句。在没有分支的代码块中,并且打印没有被缓冲,如果一个print语句在崩溃之前产生输出,而另一个没有,则崩溃位于它们之间。

另一种技术是解释崩溃转储:机器寄存器,指令指针周围的字节,调用跟踪等。如果您从崩溃中获得该信息,则通常可以确定崩溃的位置,并通过查看机器代码和寄存器的值,你可以猜测C变量和数据结构在做什么。

祝你好运。

+0

感谢Kaz,我调试了我的程序,崩溃是由于我为我的字符串分配内存的方式。设备不再崩溃,但是我得到了来自copy_to_user()函数的段错误。我怀疑我得到这个错误,因为我没有使用传递的count变量。感谢捆绑花时间看我的代码! – 2012-03-13 04:53:50

+1

但你在写程序中有分配;你说它在阅读时崩溃了。写例程中的主要问题是'kmalloc'在它可以返回的块的大小方面非常有限。它返回物理上连续的页面(这是一个宝贵的资源)。但是,对“读”的争论可能非常大。即一般来说,使用用户空间中的值作为'kmalloc'大小(除了知道它在做什么的根特权服务器程序之外)并不是一个好主意。即使有很多内存,也要做好空回的准备。 – Kaz 2012-03-13 07:16:26

+0

嗯,我只想打印出一些像“Hi There”这样的小东西,并用kmalloc分配字节,这样可以防止它崩溃。现在我不想寻找一个功能齐全的驱动程序来实现写入。我只是想先阅读才能工作。这是我写的第一个实现读/写的驱动程序。我在2周前才开始学习。 – 2012-03-13 20:11:34

在达到dev_read之前,事情可能会出错。你有没有在控制台上看到你的消息KERN_ALERT

显然这并不是所有的源代码,因为模块已初始化,字符设备已注册,并且还有其他功能,如打开例程。是什么让你认为这个错误在dev_read之中,仅仅是因为从设备上读取设备会导致设备崩溃?

sizeof(my_string)sizeof(char *)这是4或8.您正在使用指针的大小。如果你使用的是64位内核,那么当你进行调试的时候,你最多可以得到Hi there而不是!。 :)

I.e.很明显,您可能会从C基础知识中的教程中获益,例如数组和指针之间的区别。

+0

哦,你是我在指针的大小之前犯过这个错误,我忘记了这一点。我会加入其他来源。 – 2012-03-13 01:24:12

只看代码就看不出来,你可以自己帮忙检查错误。在条件可能失败的所有地方,您可以使用KERN_ERR打印错误,并且可以添加goto OUT(其中OUT:返回-1),以便尽可能减少崩溃。这可以明确告诉您错误的位置。首先创建只写功能,并检查它是否正常工作,然后开始制作dev_read函数。