2012-03-13 155 views
2

我正在製作一個簡單的字符驅動程序,它假定寫入到我的字符設備「/ 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); 

回答

2

看着你現在發佈的完整代碼,我沒有看到任何明顯的崩潰原因。你正在做的事情在其他驅動程序中完成。

只是一些觀察。

有很少的錯誤檢查。這會咬你,因爲成功執行下一件事通常取決於成功執行前一件事情的先決條件。

另外,如果確實讀取函數的調用沒有發生崩潰,您會發現它不會產生任何內容,因爲您返回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

3

在達到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

1

只看代碼就看不出來,你可以自己幫忙檢查錯誤。在條件可能失敗的所有地方,您可以使用KERN_ERR打印錯誤,並且可以添加goto OUT(其中OUT:返回-1),以便儘可能減少崩潰。這可以明確告訴您錯誤的位置。首先創建只寫功能,並檢查它是否正常工作,然後開始製作dev_read函數。